为何Haskell中take' 5 (repeat' 3)不会无限执行?
为什么
take' 5 (repeat' 3)不会无限执行? 先看我们定义的两个函数:
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
核心原因就是Haskell的惰性求值——按需计算,只有当值被实际用到时才会触发计算,而take'的逻辑刚好控制了需要计算的量:
先看
repeat' 3:它的定义是3 : repeat' 3,但这个表达式不会立刻递归到底。它更像一个"待兑现的承诺":- 当你需要列表的第一个元素时,它给你
3; - 当你需要列表剩下的部分(也就是
xs)时,它才会去计算下一个repeat' 3。
- 当你需要列表的第一个元素时,它给你
再看
take'的执行流程:- 调用
take' 5 (repeat' 3),此时n=5>0,列表不是空的,匹配第三个模式,得到3 : take' 4 (repeat' 3)——这里只需要repeat' 3的第一个元素3,剩下的repeat' 3暂时不用管; - 接下来计算
take' 4 (repeat' 3),同样只取repeat' 3的第一个元素3,得到3 : take' 3 (repeat' 3); - 重复这个过程,直到
n=1时,得到3 : take' 0 (repeat' 3); - 当调用
take' 0 (repeat' 3)时,匹配第一个模式,直接返回[],完全不需要再去处理repeat' 3的部分。
- 调用
整个过程里,repeat'从来没有被完整执行过——它只生成了take'需要的5个3,当take'的n减到0后,不再需要更多元素,repeat'的递归自然就不会继续触发了。
内容的提问来源于stack exchange,提问作者SK7
相关产品推荐
相关产品推荐

