为什么这个Haskell过滤器会终止?

时间:2012-10-29 22:09:44

标签: haskell ghc lazy-evaluation ghci

我不明白为什么以下Haskell代码在GHCi下终止:

let thereExists f lst = (filter (==True) (map f lst)) /= []
thereExists (\x -> True) [1..]

我没想到过滤器的调用永远不会完成,因为它的第二个参数是无限的,我不认为比较可以在lhs完全计算之前发生。发生了什么?

1 个答案:

答案 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