【问题标题】:Short circuiting (&&) in HaskellHaskell 中的短路 (&&)
【发布时间】:2009-11-22 14:52:21
【问题描述】:

最近一直困扰着我的一个快速问题。 Haskell 是否在一个返回布尔值的函数中执行所有等价测试,即使返回一个错误值?

例如

f a b = ((a+b) == 2) && ((a*b) == 2)

如果第一个测试返回 false,它会在 && 之后执行第二个测试吗?还是 Haskell 懒得不去做就继续前进?

【问题讨论】:

    标签: haskell boolean combinators


    【解决方案1】:

    应该像其他语言一样短路。在 Prelude 中是这样定义的:

    (&&)                    :: Bool -> Bool -> Bool
    True  && x              =  x
    False && _              =  False
    

    因此,如果第一个参数为 False,则永远不需要评估第二个参数。

    【讨论】:

    • 在列表推导的情况下是否也一样?
    • Short circuit 发音不正确。您根本不知道这些值是否经过评估,因为您无法证明它没有副作用,但除非需要,否则它们不太可能这样做。
    • 我认为它与 C++ 相同:该语言说右侧不会被评估。但是当然,如​​果编译器可以判断没有任何副作用,它无论如何都会评估它——一些 C++ 编译器会这样做,因为条件分支很昂贵。
    • 请注意,在 Haskell 中评估 thunk 可能有副作用:错误或无限循环。因此,就像 C++ 一样,编译器必须首先检查可能的副作用,如果它想要评估技术上不应该评估的东西。
    • 是的,它在列表推导中的工作方式相同。 Haskell 是一种纯语言。由于此函数未在 monad 中定义,因此不会有副作用。一个好的测试应该是这样的: False && (length [1..])
    【解决方案2】:

    就像 Martin 所说,具有惰性求值的语言从不评估任何不是立即需要的值。在像 Haskell 这样的惰性语言中,你可以免费获得短路。在大多数语言中,||和 && 和类似的运算符必须专门内置到语言中,以使它们短路评估。然而,在 Haskell 中,惰性求值使得这变得不必要。你甚至可以定义一个让自己短路的函数:

    scircuit fb sb = if fb then fb else sb

    这个函数的行为就像逻辑“或”运算符一样。这里是如何 ||在 Haskell 中定义:

    True  || _ = True
    False || x = x
    

    所以,为了给您问题的具体答案,不。如果 || 的左侧是真的,右手边永远不会被评估。您可以将两个和两个放在一起用于“短路”的其他运算符。

    【讨论】:

      【解决方案3】:

      正如 Caleb 所说,“证明”Haskell DO 有短路的简单测试。

      如果你试图在一个无限列表上运行求和,你会得到堆栈溢出:

      Prelude> foldr (+) 0 $ repeat 0
      *** Exception: stack overflow
      

      但是如果你运行例如(||)(逻辑或)在无限列表中,由于短路,您很快就会得到结果:

      Prelude> foldr (||) False $ repeat True
      True
      

      【讨论】:

      • 有趣。这对我来说有点难以接受,因为 foldr 在列表的最后一个元素中使用了第二个参数和函数。由于在这种情况下这是一个无限列表,因此考虑此函数的应用有点奇怪。谢谢你的澄清。
      【解决方案4】:

      惰性求值意味着在真正需要之前什么都不求值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-27
        相关资源
        最近更新 更多