是运算符 && Haskell 严格吗?
例如,我有一个操作 fnB :: a -> Bool
在 fnA :: Bool
返回 False
之前没有任何意义。在 CI 中,可以将这两个操作组合在一个 if
块中:
if( fnA && fnB(a) ){ doSomething; }
并且 C 将保证 fnB
在 fnA
返回 false 之前不会执行。
但是 Haskell 是懒惰的,并且通常无法保证哪个操作将首先执行,直到我们不使用 seq
、$!
或其他东西来使我们的代码严格。一般来说,这就是我们快乐所需要的。但是使用 &&
运算符,我希望在 fnA
返回其结果之前不会评估 fnB
。 Haskell 是否通过 &&
提供这样的保证?即使 fnA
返回 False,Haskell 也会计算 fnB
吗?
For example, I have an operation fnB :: a -> Bool
that makes no sense until fnA :: Bool
returns False
. In C I may compose these two operations in one if
block:
if( fnA && fnB(a) ){ doSomething; }
and C will guarantee that fnB
will not execute until fnA
returns false.
But Haskell is lazy, and, generally, there is no guarantee what operation will execute first, until we don't use seq
, $!
, or something else to make our code strict. Generally, this is what we need to be happy. But using &&
operator, I would expect that fnB
will not be evaluated until fnA
returns its result. Does Haskell provide such a guarantee with &&
? And will Haskell evaluate fnB
even when fnA
returns False?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
仅当函数
(&&)
第一个参数为True
时,其第二个参数才是严格的。它的第一个论点总是严格的。这种严格/惰性保证了评估的顺序。所以它的行为与 C 完全一样。不同之处在于,在 Haskell 中,
(&&)
是一个普通函数。在C语言中,这是不可能的。这是不正确的。真相更深层次。
严格速成班:
我们知道
(&&)
在其第一个参数中是严格的,因为:这里,⊥ 类似于
undefined
或无限循环(⊥ 发音为“bottom”)。我们还知道(False &&)
在其第二个参数中是非严格的:它不可能计算其第二个参数,因为它的第二个参数是无法计算的 ⊥ 。然而,函数
(True &&)
在其第二个参数中是严格的,因为:因此,我们说
(&&)
在其第二个参数中始终是严格的仅当第一个参数为True
时,第一个参数才在第二个参数中严格。求值顺序:
对于
(&&)
,其严格属性足以保证执行顺序。情况并非总是如此。例如,(+)::Int ->整数-> Int
在两个参数中始终是严格的,因此可以首先计算任一参数。但是,您只能通过捕获IO
monad 中的异常或者使用unsafe
函数来区分。The function
(&&)
is strict in its second argument only if its first argument isTrue
. It is always strict in its first argument. This strictness / laziness is what guarantees the order of evaluation.So it behaves exactly like C. The difference is that in Haskell,
(&&)
is an ordinary function. In C, this would be impossible.This is not correct. The truth is deeper.
Crash course in strictness:
We know
(&&)
is strict in its first parameter because:Here, ⊥ is something like
undefined
or an infinite loop (⊥ is pronounced "bottom"). We also know that(False &&)
is non-strict in its second argument:It can't possibly evaluate its second argument, because its second argument is ⊥ which can't be evaluated. However, the function
(True &&)
is strict in its second argument, because:So, we say that
(&&)
is always strict in its first argument, and strict in its second argument only when the first argument isTrue
.Order of evaluation:
For
(&&)
, its strictness properties are enough to guarantee order of execution. That is not always the case. For example,(+) :: Int -> Int -> Int
is always strict in both arguments, so either argument can be evaluated first. However, you can only tell the difference by catching exceptions in theIO
monad, or if you use anunsafe
function.正如其他人所指出的,自然
(&&)
在其参数之一上是严格的。根据标准定义,它的第一个参数是严格的。您可以使用flip
来翻转语义。作为附加说明:请注意,
(&&)
的参数不能有副作用,因此只有两个原因让您需要关心x && 是否有效。 y
在y
中是严格的:y
需要很长时间来计算。y
可以是底部。As noted by others, naturally
(&&)
is strict in one of its arguments. By the standard definition it's strict in its first argument. You can useflip
to flip the semantics.As an additional note: Note that the arguments to
(&&)
cannot have side effects, so there are only two reasons why you would want to care whetherx && y
is strict iny
:y
takes a long time to compute.y
can be bottom.。 不完全是这样。 Haskell 是纯粹的(除了
unsafePerformIO
和IO
的实现),并且没有办法观察操作将首先执行(unsafePerformIO
和IO
的实现除外)。执行顺序对于结果来说根本不重要。&&
有一个 9 值真值表,包括一个或两个参数都未定义
的情况,并且它准确地定义了操作:只要实现如下那个表,它可以按照它想要的任何顺序执行。
(如果您研究该表,您会发现顺序实现无法遵循它,除非它先执行
a
,然后执行b
iffa
为 True,但 Haskell 实现并不要求是连续的!允许只要b
执行即可。想要;你唯一的保证是,根据表格,仅当a
为 True 时,执行b
的结果才会影响您的程序。)(请注意,“惰性”是编写函数的唯一方法 完全有像上面这样的真值表;在 C 或 ML 这样的语言中,任一参数中带有
undefined
的所有五行都将强制具有undefined
作为结果,在 Haskell 中(以及在 C 中,因为&&
内置于 C 语言中)其中一行可以将False
作为结果。)Not quite. Haskell is pure (except for
unsafePerformIO
and the implementation ofIO
), and there is no way to observe which operation will execute first (except forunsafePerformIO
and the implementation ofIO
). The order of execution simply does not matter for the result.&&
has a 9-value truth table, including the cases where one or both arguments areundefined
, and it defines the operation exactly:As long as the implementation follows that table, it's allowed to execute things in any order it wants.
(If you study the table, you'll notice that there's no way for a sequential implementation to follow it unless it executes
a
first, thenb
iffa
is True. But Haskell implementations are not required to be sequential! An implementation is always allowed to kick of execution ofb
whenever it wants; your only guarantee is that, according to the table, the result of executingb
can only impact your program whena
is True.)(Note that 'laziness' is the only way to write a function with a truth table like the above at all; in a language like C or ML, all five of the lines with
undefined
in either argument would be force to haveundefined
as the result, where in Haskell (and in C, because&&
is built in to the C language) one of the lines can haveFalse
as the result instead.)我相信它会按照你期望的方式工作;当且仅当 LHS 评估为 True 时评估 RHS。然而,假设 RHS 没有副作用,您如何知道(或关心)?
编辑:我猜 RHS 可能是
未定义
,然后你会关心......I believe it works the way you expect; evaluate the RHS iff the LHS evaluates to True. However, assuming the RHS has no side-effects, how would you know (or care)?
Edit: I guess the RHS could be
undefined
, and then you would care...