为什么连懒惰的褶皱都如此渴望?

Why are even lazy folds so eager?

此代码:

import Data.Foldable
import Debug.Trace

factors :: [Bool]
factors = [True, True, False, True, True, True, True, True]

andy :: Bool -> Bool -> Bool
andy False _ = False
andy True False = False
andy True True = True

tandy :: Bool -> Bool -> Bool 
tandy a b = let c = a `andy` b in trace (show a ++ " & " ++ show b ++ " = " ++ show c) c

wonder :: Bool
wonder = foldl tandy True factors

当我评估 wonder 时说:

True & True = True  
True & True = True  
True & False = False
False & True = False
False & True = False
False & True = False
False & True = False
False & True = False

但我希望它早点停止。我已经尝试用所有可以想象的东西代替 foldl 并用 && 代替 andy 但它似乎从来没有得到提示。

在我看来,andy False _ = False 行并没有要求编译器评估第二个参数。我没有强迫任何严格。这是怎么回事?即使是 C 也可以做得更好。

tandy 在两个参数中都是严格的,即使 andy 不是。这是因为跟踪。您要求它在对 trace 的调用中显示两个输入,因此它必须评估两个参数。

考虑“tandy2”:

tandy2 :: Bool -> Bool -> Bool
tandy2 False _ = trace ("False & anything = False") False
tandy2 True b = trace ("True & " ++ show b ++ " = False") b

与其在跟踪中盲目地评估两个参数,不如谨慎地只评估它本来会评估的相同参数。这使得它实际上反映了与 andy 相同的严格属性。

尝试将 tandy2foldr 结合使用,您会发现它在遇到 False 时立即停止计算。

$ ghci
GHCi, version 9.2.1: https://www.haskell.org/ghc/  :? for help
ghci> import Debug.Trace
ghci> let tandy2 False _ = trace ("False & anything = False") False ; tandy2 True b = trace ("True & " ++ show b ++ " = False") b
ghci> foldr tandy2 True []
True
ghci> foldr tandy2 True [True]
True & True = False
True
ghci> foldr tandy2 True [True, False]
False & anything = False
True & False = False
False
ghci> foldr tandy2 True [True, False, True]
False & anything = False
True & False = False
False

给你。它从不多次计算 False 分支。