最近一直困扰着我的一个快速问题。Haskell 是否在一个返回布尔值的函数中执行所有等价测试,即使返回一个错误值?
例如
f a b = ((a+b) == 2) && ((a*b) == 2)
如果第一个测试返回 false,它会在 ? 之后执行第二个测试&&
?或者 Haskell 是否足够懒惰以至于不这样做并继续前进?
最近一直困扰着我的一个快速问题。Haskell 是否在一个返回布尔值的函数中执行所有等价测试,即使返回一个错误值?
例如
f a b = ((a+b) == 2) && ((a*b) == 2)
如果第一个测试返回 false,它会在 ? 之后执行第二个测试&&
?或者 Haskell 是否足够懒惰以至于不这样做并继续前进?
应该像其他语言一样短路。在 Prelude 中是这样定义的:
(&&) :: Bool -> Bool -> Bool
True && x = x
False && _ = False
因此,如果第一个参数为 False,则永远不需要评估第二个参数。
就像马丁说的那样,具有惰性评估的语言永远不会评估任何不是立即需要的价值。在像 Haskell 这样的惰性语言中,你可以免费获得短路。在大多数语言中,|| 和 && 和类似的运算符必须专门内置到语言中,以使它们短路评估。然而,在 Haskell 中,惰性求值使得这变得不必要。您甚至可以定义一个使自己短路的函数:
scircuit fb sb = if fb then fb else sb
此函数的行为就像逻辑“或”运算符一样。这里是如何 || 在 Haskell 中定义:
True || _ = True
False || x = x
因此,为了给您问题的具体答案,不。如果 || 的左侧 是真的,右手边永远不会被评估。对于“短路”的其他运算符,您可以将两个和两个放在一起。
正如 Caleb 所说,一个简单的测试来“证明”Haskell DO 有短路。
如果您尝试在无限列表上运行求和,您将得到堆栈溢出:
Prelude> foldr (+) 0 $ repeat 0
*** Exception: stack overflow
但是如果你(||)
在无限列表中运行 eg (logical OR) on,你很快就会得到一个结果,因为短路:
Prelude> foldr (||) False $ repeat True
True
惰性评估意味着,在真正需要之前什么都不做。