是运算符 && Haskell 严格吗?

发布于 2024-12-07 07:33:42 字数 596 浏览 0 评论 0原文

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

if( fnA && fnB(a) ){ doSomething; }

并且 C 将保证 fnBfnA 返回 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

病毒体 2024-12-14 07:33:42

仅当函数 (&&) 第一个参数为 True 时,其第二个参数才是严格的。它的第一个论点总是严格的。这种严格/惰性保证了评估的顺序。

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

但是 Haskell 很懒,而且通常无法保证哪个操作会先执行,除非我们不使用 seq、$! 或其他东西来使我们的代码变得严格。

这是不正确的。真相更深层次。

严格速成班:

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

⊥ && x = ⊥

这里,⊥ 类似于 undefined 或无限循环(⊥ 发音为“bottom”)。我们还知道 (False &&) 在其第二个参数中是非严格的:

False && ⊥ = False

它不可能计算其第二个参数,因为它的第二个参数是无法计算的 ⊥ 。然而,函数 (True &&) 在其第二个参数中是严格的,因为:

True && ⊥ = ⊥

因此,我们说 (&&) 在其第二个参数中始终是严格的仅当第一个参数为 True 时,第一个参数才在第二个参数中严格。

求值顺序:

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

The function (&&) is strict in its second argument only if its first argument is True. 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.

But Haskell is lazy, and, generally, there are no guarantee what operation will execute first, until we don't use seq, $!, or something else to make our code strict.

This is not correct. The truth is deeper.

Crash course in strictness:

We know (&&) is strict in its first parameter because:

⊥ && x = ⊥

Here, ⊥ is something like undefined or an infinite loop (⊥ is pronounced "bottom"). We also know that (False &&) is non-strict in its second argument:

False && ⊥ = False

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:

True && ⊥ = ⊥

So, we say that (&&) is always strict in its first argument, and strict in its second argument only when the first argument is True.

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 the IO monad, or if you use an unsafe function.

耀眼的星火 2024-12-14 07:33:42

正如其他人所指出的,自然 (&&) 在其参数之一上是严格的。根据标准定义,它的第一个参数是严格的。您可以使用 flip 来翻转语义。

作为附加说明:请注意,(&&) 的参数不能有副作用,因此只有两个原因让您需要关心 x && 是否有效。 yy 中是严格的:

  • 性能:如果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 use flip 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 whether x && y is strict in y:

  • Performance: If y takes a long time to compute.
  • Semantics: If you expect that y can be bottom.
天生の放荡 2024-12-14 07:33:42

Haskell 是惰性的,并且通常无法保证哪个操作将首先执行

。 不完全是这样。 Haskell 是纯粹的(除了 unsafePerformIOIO 的实现),并且没有办法观察操作将首先执行(unsafePerformIOIO 的实现除外)。执行顺序对于结果来说根本不重要。

&& 有一个 9 值真值表,包括一个或两个参数都 未定义 的情况,并且它准确地定义了操作:

a           b           a && b
True        True        True
True        False       False
True        undefined   undefined
False       True        False
False       False       False
False       undefined   False
undefined   True        undefined
undefined   False       undefined
undefined   undefined   undefined

只要实现如下那个表,它可以按照它想要的任何顺序执行。

(如果您研究该表,您会发现顺序实现无法遵循它,除非它先执行a,然后执行b iff a 为 True,但 Haskell 实现并不要求是连续的!允许只要 b 执行即可。想要;你唯一的保证是,根据表格,仅当 a 为 True 时,执行 b 的结果才会影响您的程序。)

(请注意,“惰性”是编写函数的唯一方法 完全有像上面这样的真值表;在 C 或 ML 这样的语言中,任一参数中带有 undefined 的所有五行都将强制具有 undefined 作为结果,在 Haskell 中(以及在 C 中,因为&& 内置于 C 语言中)其中一行可以将 False 作为结果。)

Haskell is lazy, and, generally, there is no guarantee what operation will execute first

Not quite. Haskell is pure (except for unsafePerformIO and the implementation of IO), and there is no way to observe which operation will execute first (except for unsafePerformIO and the implementation of IO). 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 are undefined, and it defines the operation exactly:

a           b           a && b
True        True        True
True        False       False
True        undefined   undefined
False       True        False
False       False       False
False       undefined   False
undefined   True        undefined
undefined   False       undefined
undefined   undefined   undefined

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, then b iff a is True. But Haskell implementations are not required to be sequential! An implementation is always allowed to kick of execution of b whenever it wants; your only guarantee is that, according to the table, the result of executing b can only impact your program when a 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 have undefined as the result, where in Haskell (and in C, because && is built in to the C language) one of the lines can have False as the result instead.)

煮茶煮酒煮时光 2024-12-14 07:33:42

我相信它会按照你期望的方式工作;当且仅当 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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文