【发布时间】:2021-08-01 09:18:27
【问题描述】:
我一直在研究 Graham Hutton 在 Haskell 中的编程。它指出
函数
map将函数应用于列表的所有元素
好的,有道理。当然符合我对其他语言地图的了解。
其中一个练习是实现all :: (a -> Bool) -> [a] -> Bool。
有时,如果不懒惰地完成,天真的实现可能会无限循环。例如all (<10) [1..]。所以我的第一个实现是:
all p [] = True
all p (x:xs) | not (p x) = False
| otherwise = all' p xs
但后来我考虑尝试使用 map 和 and 的函数组合来看看 Haskell 中的非终止程序会做什么:
all' :: (a -> Bool) -> [a] -> Bool
all' p = and . map p
令我惊讶的是,all' (<10) [1..] 很快就返回了False。我实际上希望map 在应用and 之前尝试创建一个无限列表——类似于and [p x | x <- xs, p x]。
这种终止行为意味着map 实际上正在创建类似于and 正在处理的流的东西。 map 实际上是懒惰的(因此描述是错误的)还是我在第二次实现中误解了其他内容?
【问题讨论】:
-
列表理解也是惰性的,所以
and [p x | x <- xs]将在列表中有False的那一刻终止。如果您使用and [p x | x <- xs, p x],则不会在无限列表上终止,因为您使用p x进行过滤,因此只会在列表中返回Trues。 -
在 Haskell 中,你应该假设一切都是惰性的,除非有其他证据/文档。
-
@LouisWasserman 很高兴知道。很棒的提示 - 谢谢。
标签: haskell lazy-evaluation higher-order-functions