在Haskell中运算符&&严格吗?

Dmi*_*lov 15 haskell logical-operators strictness

例如,我有一个fnB :: a -> BoolfnA :: Bool返回之前没有意义的操作False.CI中可以将这两个操作组合在一个if块中:

if( fnA && fnB(a) ){ doSomething; }
Run Code Online (Sandbox Code Playgroud)

和C将保证fnBfnA返回false 之前不会执行.

但Haskell是惰性的,并且,通常也不能保证什么操作将首先执行,直到我们不使用seq,$!或别的东西,使我们的代码严格.一般来说,这就是我们需要快乐的事情.但是使用&&运算符,我希望fnBfnA返回结果之前不会对其进行求值.Haskell提供这样的保证&&吗?fnB即使fnA返回False,Haskell也会评估吗?

Die*_*Epp 32

(&&)仅当第一个参数为第二个参数时,该函数才是严格的True.它的第一个论点总是严格的.这种严格/懒惰是保证评估顺序的原因.

所以它的行为与C完全相同.不同之处在于Haskell中(&&)是一个普通的函数.在C中,这是不可能的.

但是Haskell是懒惰的,并且通常不能保证首先执行什么操作,直到我们不使用seq,$!或其他东西来使我们的代码严格.

这是不正确的.事实更深刻.

严格的速成课程:

我们知道(&&)它的第一个参数是严格的,因为:

? && x = ?
Run Code Online (Sandbox Code Playgroud)

在这里,⊥是类似的undefined或无限循环(⊥发音为"bottom").我们也知道(False &&)第二个论点是非严格的:

False && ? = False
Run Code Online (Sandbox Code Playgroud)

它不可能评估它的第二个参数,因为它的第二个参数是⊥,它不能被评估.但是,该函数(True &&)在其第二个参数中是严格的,因为:

True && ? = ?
Run Code Online (Sandbox Code Playgroud)

所以,我们说(&&)第一个参数总是严格的,第二个参数只有第一个参数时才严格True.

评估顺序:

因为(&&),它的严格属性足以保证执行顺序.情况并非总是如此.例如,(+) :: Int -> Int -> Int两个参数中始终都是严格的,因此可以首先计算任一参数.但是,您只能通过捕获IOmonad中的异常或使用unsafe函数来区分.

  • @larsmans:实际上,任何在不对其进行评估的情况下返回值的函数在该参数中都是*严格的*strict.例如,函数`id`在其参数中始终是严格的. (7认同)

小智 5

正如其他人所指出的那样,(&&)其中一个论点自然是严格的.按照标准定义,它的第一个论点是严格的.您可以使用flip翻转语义.

作为补充说明:请注意,参数(&&)不能产生副作用,因此只有两个原因可以解释为什么要x && y严格遵守y:

  • 性能:如果y需要很长时间来计算.
  • 语义:如果你认为y可以是最低点.