【发布时间】:2009-11-22 14:52:21
【问题描述】:
最近一直困扰着我的一个快速问题。 Haskell 是否在一个返回布尔值的函数中执行所有等价测试,即使返回一个错误值?
例如
f a b = ((a+b) == 2) && ((a*b) == 2)
如果第一个测试返回 false,它会在 && 之后执行第二个测试吗?还是 Haskell 懒得不去做就继续前进?
【问题讨论】:
标签: haskell boolean combinators
最近一直困扰着我的一个快速问题。 Haskell 是否在一个返回布尔值的函数中执行所有等价测试,即使返回一个错误值?
例如
f a b = ((a+b) == 2) && ((a*b) == 2)
如果第一个测试返回 false,它会在 && 之后执行第二个测试吗?还是 Haskell 懒得不去做就继续前进?
【问题讨论】:
标签: haskell boolean combinators
应该像其他语言一样短路。在 Prelude 中是这样定义的:
(&&) :: Bool -> Bool -> Bool
True && x = x
False && _ = False
因此,如果第一个参数为 False,则永远不需要评估第二个参数。
【讨论】:
Short circuit 发音不正确。您根本不知道这些值是否经过评估,因为您无法证明它没有副作用,但除非需要,否则它们不太可能这样做。
就像 Martin 所说,具有惰性求值的语言从不评估任何不是立即需要的值。在像 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
但是如果你运行例如(||)(逻辑或)在无限列表中,由于短路,您很快就会得到结果:
Prelude> foldr (||) False $ repeat True
True
【讨论】:
惰性求值意味着在真正需要之前什么都不求值。
【讨论】: