理解Haskell中的直接自引用

时间:2015-08-27 11:53:02

标签: haskell

我刚开始学习Haskell几个小时,试图理解这一点 The Fibonacci sequence确实:

fibs = 0 : 1 : next fibs
  where
    next (a : t@(b:_)) = (a+b) : next t

next函数对我来说很奇怪,它最终会得到一些"无效"输入,就像起初一样:

next (0:1) = (0+1) : next [1]

但后来next ([1])无法使用,因为t@(b:_)中没有输入。那么next如何运作?

我的下一个困惑是fib本身,因为它假设是一个斐波那契序列,我假设在第一步之后会得到fibs = 0 : 1 : 1 : next fibs但是我们需要计算next([0, 1, 1])女巫给(0+1): next([1, 1]) == 1 : next([1, 1]),我们得到初始元素1,所以在next([0, 1, 1])中,列表的第一个值(在下一个文件中)将为1,但是将这个1附加到原始的fib上,我们得到的0 : 1 : 1 : 1不是Fibonacci序列。

我认为我误解了某些东西,它实际上是如何运作的?

2 个答案:

答案 0 :(得分:4)

定义递归定义结果的标准方法是从undefined开始近似这样的值,并从那里展开递归,如下所示:

-- A function describing the recursion
f x = 0 : 1 : next x

fibs0 = undefined
fibs1 = f fibs0 = 0 : 1 : next undefined 
      -- next requires at least 2 elements
      = 0 : 1 : undefined
fibs2 = f fibs1 = 0 : 1 : next fibs1
      = 0 : 1 : next (0 : 1 : undefined)
      = 0 : 1 : 1 : next (1 : undefined)
      -- next requires at least 2 elements
      = 0 : 1 : 1 : undefined
fibs3 = f fibs2 = 0 : 1 : next fibs2
      = 0 : 1 : next (0 : 1 : 1 : undefined)
      = 0 : 1 : 1 : next (1 : 1 : undefined)
      = 0 : 1 : 1 : 2 : next (1 : undefined)
      -- next requires at least 2 elements
      = 0 : 1 : 1 : 2 : undefined
fibs4 = f fibs3 = 0 : 1 : next fibs3
      = 0 : 1 : next (0 : 1 : 1 : 2 : undefined)
      ...

如果我们继续前进,我们将接近完整序列"在极限",逐步逼近它。这个非正式的论证可以通过克林的不动点定理正式证明。

答案 1 :(得分:0)

next函数实际上会生成fibs - 所以它不会调用next [0, 1, 1]来调用next (0 : 1 : 1 : next rest)

图片中发生了什么:

fib = 0 : 1 : not-yet-evaluated-part
fib = 0 : 1 : [+] : not-yet-evaluated-part
      ^   ^    |
      *---*----* (applying next to fib)
fib = 0 : 1 : 1 : [+] : not-yet-evaluated-part
          ^   ^    |
          *---*----* (next calls itself)
fib = 0 : 1 : 1 : 2 : [+] : not-yet-evaluated-part
              ^   ^    |
              *---*----* (etc)

next是“铁路建设者列车”,需要一些初始轨道才能运行(0 : 1 : ...)。

因为有[] - 列表的末尾无处放置在fibs列表中,它将无限。

但是,我建议你从不太模糊的事情开始 - 例如,你应该尝试单独理解列表。