我是新来的学生,正在学习计算机科学。我们正在处理Haskell,虽然我了解Haskell的想法,但似乎无法弄清楚我们应该看待的代码片段是如何工作的:
module U1 where
double x = x + x
doubles (d:ds) = (double d):(doubles ds)
ds = doubles [1..]
我承认,对于知道发生了什么事的人来说,这似乎很简单,但是我无法全神贯注。如果我写“ take 5 ds”,它显然会返回[2,4,6,8,10]。我不明白的是为什么。
这是我的思路:我叫ds,然后寻找双打。因为我还提交了[1 ..]值,所以double(d:ds)应该意味着d = 1且ds = [2 ..],对吗?然后,我将d加倍,返回2并将其放在列表的开头(数组?)。然后,它调用自身,将ds = [2 ..]转换为d = 2和ds = [3 ..],然后再次将d加倍,并再次调用自身,依此类推,以此类推,直到可以返回5个值, [2,4,6,8,10]。
所以首先,我的理解正确吗?我的思路中有严重错误吗?其次,由于似乎将所有doubled都保存到列表中供以后调用,所以该列表的名称是什么?我在哪里准确定义它?
在此先感谢您,希望您能帮助学生理解这个x)
我认为您对递归/循环部分的理解是正确的,该部分涉及如何doubles
遍历无限列表的每个元素。
现在关于
似乎将所有double d保存到列表中供以后调用,该列表的名称是什么?我在哪里准确定义它?
这与在Haskell中称为“惰性评估”的功能有关。该列表未预先计算并存储在任何位置。相反,您可以想象一个列表是C ++中的一个函数对象,可以在需要时生成元素。(您可能会看到的正常语言是根据需要对表达式进行求值)。所以当你这样做
take 5 [1..]
[1..]
可以看作是与head
,take
等一起使用时生成数字的函数对象。因此,
take 5 [1..] == (1 : take 4 [2..])
这[2..]
也是给您编号的“功能对象”。同样,您可以
take 5 [1..] == (1 : 2 : take 3 [3..]) == ... (1 : 2 : 3 : 4 : 5 : take 0 [6..])
现在,我们并不需要关心[6..]
的,因为take 0 xs
对于任何xs
是[]
。因此,我们可以
take 5 [1..] == (1 : 2 : 3 : 4 : 5 : [])
无需存储任何“无限”列表,例如[2..]
。如果您想了解延迟计算的实际发生方式,可以将它们视为函数对象/生成器。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句