大多数其他语言都使用call-by-value。 Haskell使用call-by-name(懒惰评估),我很想知道它是如何运行的,我认为与call-by-value相比会更好。
举一个问题的例子,
重复'函数定义为:
repeat' :: a -> [a]
repeat' x = x:repeat' x
使用repeat' 3
将获得3个无限列表,
ghci> repeat' 3
将生成3个连续的,
但是take 5 (repeat' 3)
只会获得[3,3,3,3,3]
haskell如何知道以第五递归内部repeat'
函数结束?此外,我认为这不是take
的问题。
当代码执行哪个阶段时它与按值调用有什么不同?
感谢
答案 0 :(得分:2)
您可以获得无限的3个列表,因为在交互式会话中键入repeat' 3
实际上会调用show (repeat' 3)
,而show
会尝试迭代repeat' 3
的整个返回值。另一方面,take
仅尝试从列表中获取有限数量的元素。这是Prelude中的定义:
take n _ | n <= 0 = []
take _ [] = []
take n (x:xs) = x : take (n-1) xs
将repeat'
,repeat' x = x:repeat' x
的定义与take匹配的模式进行比较。当您致电take 5 (repeat' 3)
时,最后一种模式适用,因此它变为take 5 (3:repeat' 3) = 3 : take 4 (repeat' 3)
。由于延迟评估,repeat'
仅在任何给定步骤中根据需要进行评估,在这种情况下,这意味着提取第一个元素以匹配模式x:xs
。因此,take
会建立一个包含5个3的列表,在take 0 (repeat' 3)
匹配时终止并且递归终止,忽略对repeat'
的未评估调用以返回空列表。