在Haskell中评估递归数据的真正过程是什么?

时间:2013-11-22 01:07:16

标签: haskell recursion

我正在尝试理解递归数据,我有点困惑。我试过这个:

m = 1 : map (+1) m

这产生了一个与[1..]相同的列表。我试图像这样完成评估程序:

m = 1 : map (+1) m
  = 1 : map (+1) (1 : map (+1) m)
  = 1 : 2 : map (+1) (map (+1) m)
  = 1 : 2 : map (+1) (map (+1) (1 : 2 : map (+1) (map (+1) m)) )
  = 1 : 2 : map (+1) (2 : map (+1) (2 : (map (+1) (map (+1) m)) )
  = 1 : 2 : 3 : map (+1) (map (+1) (2 : (map (+1) (map (+1) m)))
  = 1 : 2 : 3 : map (+1) (3 : map (+1) ( (map (+1) (map (+1) m))) )
  = 1 : 2 : 3 : 4 : map (+1) (map (+1) ( (map (+1) (map (+1) m)) ))
  = ...

尾巴中有很多map (+1)个东西,随着程序的增加而增加。是否有map (+1)这么多map (+1) ...的重复计算?我读过其他提到thunk的帖子,但是如何将它们全部联系在一起呢?非常感谢你。

1 个答案:

答案 0 :(得分:1)

会发生什么更像是以下

m = 1 : map (+1) m
    1 : map (+1) (1 : _)
        ^------------<|     Points to the same thunk in memory
    1 : a : map (+1) (a : _) where a = ((+1) 1)
            ^------------<|
    1 : 2 : map (+1) (2 : _)
            ^------------<|
    1 : 2 : a : map (+1) (a : _) where a = ((+1) 2)
                ^------------<|
    1 : 2 : 3 : map (+1) (3 : _)
                ^------------<|
    1 : 2 : 3 : a : map (+1) (a : _) where a = ((+1) 3)
                    ^------------<|
    1 : 2 : 3 : 4 : map (+1) (4 : _)
                    ^------------<|

传递给map的列表中的下一个元素始终指向要生成的元素map

但是,重要的是要注意Haskell规范声明它必须是惰性的,但是实现惰性的方式取决于编译器。它可以选择将大量的这些优化成一个简单的汇编循环,或者根据输出的使用方式,它可能会进行一些循环融合,将几个遍历组合成一个。