作者:汽车一族coolboy_518 | 来源:互联网 | 2023-10-12 14:18
我一直在研究 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 实际上是懒惰的(因此描述错误)还是我在第二个实现中误解了其他东西?
回答
是map
其实懒惰(因此说明错误的),或在我的第二个实现我误解了什么东西?
map
很懒。它不会急切地将该功能应用于每个项目。事实上,所有的表达都在一定意义懒map f x
仍然map f xs
除非需要的价值。
如果我们评估map f xs
,并且我们需要例如第三个元素,它不会确定我们是否对第一个元素的值不感兴趣。f x1
列表理解也很懒惰。事实上,如果我们与:
and [p x | x <- xs]
它将从项目的那一刻起一个终止x
在xs
有False
作为p x
。然而p x
,如果你添加一个 filter ,它只会发出True
s,确实:
[p x | x <- xs, p x]
只会 yield True
,因为我们已经过滤了p x
应该为的事实True
,并且sand
的无限列表中True
的 永远不会终止,因为and
它将继续寻找一个False
值。