haskell fibonacci-无法构造无限类型:a0=[a0]

haskell fibonacci-无法构造无限类型:a0=[a0],haskell,Haskell,我试图在haskell中获得fibonacci数的无限列表,但以下代码无法编译: fib1 x = fib1 (x : (last $ init x) + (last x)) result1 = fib1 [1,2] 我最终让它使用以下代码: fib2 x y = head y : fib2 y (zipWith (+) x y) result2 = fib2 [0,1] [1,1] 不过,我不明白为什么第一个代码段没有编译。错误如下。我只是想知道为什么第一个没有编译,而第二个编译 p2.h

我试图在haskell中获得fibonacci数的无限列表,但以下代码无法编译:

fib1 x = fib1 (x : (last $ init x) + (last x))
result1 = fib1 [1,2]
我最终让它使用以下代码:

fib2 x y = head y : fib2 y (zipWith (+) x y)
result2 = fib2 [0,1] [1,1]
不过,我不明白为什么第一个代码段没有编译。错误如下。我只是想知道为什么第一个没有编译,而第二个编译

p2.hs:3:16:
    Occurs check: cannot construct the infinite type: a0 = [a0]
    In the first argument of `(:)', namely `x'
    In the first argument of `fib1', namely
      `(x : (last $ init x) + (last x))'
    In the expression: fib1 (x : (last $ init x) + (last x))

p2.hs:3:21:
    Occurs check: cannot construct the infinite type: a0 = [a0]
    In the first argument of `(+)', namely `(last $ init x)'
    In the second argument of `(:)', namely
      `(last $ init x) + (last x)'
    In the first argument of `fib1', namely
      `(x : (last $ init x) + (last x))'

p2.hs:3:44:
    Occurs check: cannot construct the infinite type: a0 = [a0]
    Expected type: [[a0]]
      Actual type: [a0]
    In the first argument of `last', namely `x'
    In the second argument of `(+)', namely `(last x)'
    In the second argument of `(:)', namely
      `(last $ init x) + (last x)' Failed, modules loaded: none.

第一个代码示例的问题是无法为其编写类型注释。它将是无限的。我们还是试试吧:

fib1x=fib1(x:(last$init x)+(last x))

首先让我们简化它,因为我们可以复制相同的问题,而不需要
last
init
之类的东西:

fib1 x=fib1(x:未定义)

fib1
的参数的类型是什么。在左边,我们只看到
x
,没有更多关于它的信息。我们可以假设它有某种类型
a
。在右侧,我们尝试使用参数调用函数,参数必须是列表(因为它是由
运算符构造的)。列表的元素以
x
开头,其类型为
a
。因此,
fib1
的参数类型是
[a]
。由于我们不能使用两种不同类型的参数调用函数,因此即使在左侧
x
也必须使用类型
[a]
。但这迫使我们将右侧的类型更新为
[[a]]
。然后又在左边。这个过程永远不会停止,类型将不断增长,因为无法将
a
[a]
统一起来。因此,表达式没有有效的类型,GHC将拒绝它

另一方面,第二个代码段没有问题

fib2 x y=头部y:fib2 y(带(+)x y的拉链)

我们可以很容易地询问GHCi该函数的类型,它会很高兴地回答我们:

Prelude>让fib2 x y=头部y:fib2 y(带(+)x y的拉链)
前奏曲>:t fib2
fib2::Num a=>[a]->[a]->[a]


该类型是完全有限的。

第一个代码示例的问题是,您无法为其编写类型注释。它将是无限的。我们还是试试吧:

fib1x=fib1(x:(last$init x)+(last x))

首先让我们简化它,因为我们可以复制相同的问题,而不需要
last
init
之类的东西:

fib1 x=fib1(x:未定义)

fib1
的参数的类型是什么。在左边,我们只看到
x
,没有更多关于它的信息。我们可以假设它有某种类型
a
。在右侧,我们尝试使用参数调用函数,参数必须是列表(因为它是由
运算符构造的)。列表的元素以
x
开头,其类型为
a
。因此,
fib1
的参数类型是
[a]
。由于我们不能使用两种不同类型的参数调用函数,因此即使在左侧
x
也必须使用类型
[a]
。但这迫使我们将右侧的类型更新为
[[a]]
。然后又在左边。这个过程永远不会停止,类型将不断增长,因为无法将
a
[a]
统一起来。因此,表达式没有有效的类型,GHC将拒绝它

另一方面,第二个代码段没有问题

fib2 x y=头部y:fib2 y(带(+)x y的拉链)

我们可以很容易地询问GHCi该函数的类型,它会很高兴地回答我们:

Prelude>让fib2 x y=头部y:fib2 y(带(+)x y的拉链)
前奏曲>:t fib2
fib2::Num a=>[a]->[a]->[a]


这种类型是完全有限的。

很好的解释@Jeff Lins,遇到类似问题的第一步是向函数中添加类型声明。(甚至养成总是添加它们的习惯)然后要么从编译器那里得到更精确的错误,要么——就像在本例中一样——自己找到问题。我不确定我是否理解这一点。在我发布问题之前,我尝试提供以下类型注释:fib1::Num a=>[a]->[a]。但很明显,这是行不通的。我不明白为什么它会把右边改成[[a]]。因为[a]:[a]应该只产生[a]。为什么要将列表包装在另一个列表中?@JeffLins您的
(:)
类型错误;它不是
[a]->[a]->[a]
,而是
a->[a]->[a]
。但即使这样,您也会遇到问题,因为
last
init
显然不会返回列表。谢谢,丹尼尔。现在这个答案对我来说非常有意义!类型混淆似乎是问题的根源。很好的解释@Jeff Lins,遇到类似问题的第一步是向函数中添加类型声明。(甚至养成总是添加它们的习惯)然后要么从编译器那里得到更精确的错误,要么——就像在本例中一样——自己找到问题。我不确定我是否理解这一点。在我发布问题之前,我尝试提供以下类型注释:fib1::Num a=>[a]->[a]。但很明显,这是行不通的。我不明白为什么它会把右边改成[[a]]。因为[a]:[a]应该只产生[a]。为什么要将列表包装在另一个列表中?@JeffLins您的
(:)
类型错误;它不是
[a]->[a]->[a]
,而是
a->[a]->[a]
。但即使这样,您也会遇到问题,因为
last
init
显然不会返回列表。谢谢,丹尼尔。现在这个答案对我来说非常有意义!类型混淆似乎是问题的根源。