哪个阶段在按名称调用和按值调用之间有所区别?

时间:2016-02-20 03:33:08

标签: haskell lazy-evaluation

大多数其他语言都使用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的问题。

当代码执行哪个阶段时它与按值调用有什么不同?

感谢

1 个答案:

答案 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'的未评估调用以返回空列表。