我正在尝试理解递归数据,我有点困惑。我试过这个:
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的帖子,但是如何将它们全部联系在一起呢?非常感谢你。
答案 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规范声明它必须是惰性的,但是实现惰性的方式取决于编译器。它可以选择将大量的这些优化成一个简单的汇编循环,或者根据输出的使用方式,它可能会进行一些循环融合,将几个遍历组合成一个。