我不明白为什么以下Haskell代码在GHCi下终止:
let thereExists f lst = (filter (==True) (map f lst)) /= []
thereExists (\x -> True) [1..]
我没想到过滤器的调用永远不会完成,因为它的第二个参数是无限的,我不认为比较可以在lhs完全计算之前发生。发生了什么?
答案 0 :(得分:17)
比较可以在完全计算LHS之前进行。只要filter
生成了一个元素,/=
就可以得出结论,该列表可能不等于[]
并立即返回True
。
/=
实现如下:
(/=) :: Eq a => [a] -> [a] -> Bool
[] /= [] = False
[] /= (y:ys) = True
(x:xs) /= [] = True
(x:xs) /= (y:ys) = (x /= y) || (xs /= ys)
由于Haskell很懒惰,我们只会根据需要选择哪些参数来选择我们将使用的右侧。对你的例子的评价是这样的:
filter (== True) (map (\x -> True) [1..]) /= []
==> (True : (filter (== True) (map (\x -> True) [2..]))) /= []
==> True
一旦我们知道/=
的第一个参数是(1 : something)
,它就会匹配上面代码中/=
的第三个等式,因此我们可以返回True
但是,如果你尝试thereExists (\x -> False) [1..]
它确实不会终止,因为在这种情况下filter
将永远不会在生成我们可以匹配的构造函数方面取得任何进展。
filter (== True) (map (\x -> False) [1..]) /= []
==> filter (== True) (map (\x -> False) [2..]) /= []
==> filter (== True) (map (\x -> False) [3..]) /= []
...
等无限。
总之,无限列表中的thereExists
可以在有限时间内返回True
,但永远不会False
。