Haskell如何知道停止在无限列表上执行递归函数?

yzuktlbb  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(81)

我正在浏览Learn You Some Haskell。在关于递归函数的章节中,作者重新定义了标准库中的两个:

take' :: (Num i, Ord i) => i -> [a] -> [a]
take' n _
    | n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n-1) xs

repeat' :: a -> [a]
repeat' x = x:repeat' x

字符串
我不明白为什么take’ 5 (repeat’ 3)不会永远运行。我理解lazy eval,但在这种情况下,我认为repeat’将永远被调用。take’如何限制它?

jgzswidk

jgzswidk1#

大多数Haskell都有一个很好的特性,你可以简单地用它们的定义替换表达式。
我们可以使用此属性来推理您提供的示例:

take’ 5 (repeat’ 3)          -- starting expression
take’ 5 (3 : repeat’ 3)      -- replace repeat’ with its definition
3 : take’ 4 (repeat’ 3)      -- replace take’ with its definition
3 : take’ 4 (3 : repeat’ 3)  -- replace repeat’ with its definition
... etc ...
3 : 3 : 3 : 3 : take’ 1 (repeat’ 3)
3 : 3 : 3 : 3 : take’ 1 (3 : repeat’ 3)
3 : 3 : 3 : 3 : 3 : take’ 0 (repeat’ 3)
3 : 3 : 3 : 3 : 3 : []

字符串

r7knjye2

r7knjye22#

在Haskell中,惰性求值使take'函数能够处理像repeat'生成的无限列表。关键是Haskell只计算需要的内容。当您调用take' 5 (repeat' 3)时,它只生成和计算无限列表的前五个元素,允许有限递归。惰性求值确保Haskell不会尝试预先生成整个无限列表,在产生所需的元素之后,使递归能够终止。

相关问题