学习Haskell地图,折叠,循环和递归

作为编程启蒙之旅的一部分(从程序到OOP到并发到现在的功能),我只是将自己的脚趾蘸到了Haskell的世界中。

我一直在尝试一个在线Haskell评估器。

不过,我现在陷入了一个问题:

创建一个简单的函数,给出数组数组的总和。

在程序语言中,这对我来说很简单(使用递归)(c#):

private int sum(ArrayList x, int i)
{
  if (!(x.Count < i + 1)) {
        int t = 0;

        t = x.Item(i);
        t = sum(x, i + 1) + t;
        return t;
    }
}

所有非常好的,但是我在Haskell失败的尝试是这样的:

let sum x = x+sum  in map sum [1..10]

这导致了以下错误(来自上述网站):

Occurs check: cannot construct the infinite type: a = a -> t

请记住,我在过去的30分钟内只使用了Haskell!

我不是简单地寻找答案,而是更多地解释它。


我不是简单地寻找答案,而是更多地解释它。

在=的左边,你可以使用sum作为应用于x的函数。 编译器不知道x的类型,因此编译器使用类型变量a来表示“ x的类型”。 因此编译器不知道函数sum的结果类型,所以它选择另一个类型变量,这个类型t来表示结果类型。 现在在左边,编译器认为x的类型是a -> t (接受a和返回t函数)。

在=的右边添加xsum 。 在Haskell中,可以添加所有类型的数字,但只有在具有相同类型时才可以添加两个数字。 所以在这里,编译器假定sum的类型与x相同,即键入a

但是在Haskell中,一个标识符有一种类型 - 可能是一种whangdilly复杂类型,但是一种类型。 这包括sum ,它的类型应该在`sign的两边相同,所以编译器试图解决方程式

a = a -> t

at没有解决这个等式的值。 它根本无法完成。 没有a这样的a等于一个接受自己作为参数的函数。 因此出现错误信息

cannot construct the infinite type: a = a -> t

即使所有的解释,这不是一个很好的错误信息,是吗?

欢迎来到Haskell :-)


PS您可能会喜欢尝试“氦气,用于学习Haskell”,这为初学者提供了更好的错误信息。


'sum'取一个值列表并将其减少为一个值。 你可以把它写成一个显式循环(记住Haskell没有循环关键字,但使用递归)。 请注意,根据列表的形状,定义有两个部分:

mysum []     = 0
mysum (x:xs) = x + mysum xs

或者更有效率地采用尾递归风格:

mysum xs = go 0 xs
   where
      go n []     = n
      go n (x:xs) = go (n+x) xs

不过,Haskell拥有丰富的控制结构库,可以在懒惰列表上运行。 在这种情况下,可以使用reduce函数将列表减少为单个值:折叠。

所以mysum可以写成:

mysum xs  = foldr (+) 0 xs

例如:

Prelude> foldr (+) 0 [1..10]
55

你的错误是使用地图,它一次转换一个列表,一个元素,而不是折叠。

我建议你首先介绍Haskell,也许是“Haskell编程”,以便了解函数式编程的核心概念。 在这个问题中描述了其他很好的介绍性材料。


你需要阅读一个好的教程,有一些大的误解。

首先我要假设你是指列表而不是数组。 数组存在于Haskell中,但它们不是初学者会遇到的。 (更不用说你正在使用[1..10],它是数字1到10的列表)。

你想要的功能实际上是内置的,并且调用sum,所以我们必须调用我们的其他东西,new_sum:

new_sum [] = 0
new_sum (h:t) = h + (sum t)
链接地址: http://www.djcxy.com/p/80791.html

上一篇: Learning Haskell maps, folds, loops and recursion

下一篇: How much time have you invested in order to have a good grasp on Haskell?