【问题标题】:What is the difference between "evaluate" and "return $!"?“评估”和“返回$!”有什么区别?
【发布时间】:2012-03-22 04:11:57
【问题描述】:

这是evaluate文档的摘录:

Control.Exception.Base.evaluate :: a -> IO a
evaluate x

不一样

return $! x

正确的定义是

evaluate x = (return $! x) >>= return

(source)

这些似乎具有相同的含义。这两个定义有什么区别?

【问题讨论】:

  • 这真的不违反单子定律吗?
  • @leftaroundabout 不,它没有。如果运行,两者的行为完全相同,但如果你 seq 表达式,return $! x 有一个 seq 最外层,而(return $! x) >>= return 有一个 (>>=) 最外层。
  • @leftaroundabout:不,因为出于法律目的,⊥ 被忽略。像 Reader 这样的标准 monad 的行为方式相同。 (我不认同 Daniel Fischer 的论点(我以前从其他人那里听说过),因为“如果运行,行为完全相同”并不是一个定义明确的概念。)
  • @DanielFischer 我不确定您的陈述是否正确。 `seq` 的优先级低于 >>= - >>= 怎么可能是最外层的?
  • @mucaho 我说的是两个表达式,它们将成为seq 的参数。在seq (return $! x) 中,return $! x 在最外面有一个seq [来自$!],而在seq ((return $! x) >>= return) 中,(return $! x) >>= return 在最外面有一个>>=

标签: haskell io monads evaluation io-monad


【解决方案1】:

快速参考:

evaluate的类型是:

evaluate :: a -> IO a

seq 的类型为 a -> b -> b。它首先计算第一个参数,然后返回第二个参数。

评估遵循以下三个规则:

evaluate x `seq` y    ==>  y
evaluate x `catch` f  ==>  (return $! x) `catch` f
evaluate x >>= f      ==>  (return $! x) >>= f

return $! x(return $! x) >>= return 之间的区别通过以下表达式变得明显:

evaluate undefined `seq` 42

根据第一条规则,它的计算结果必须为 42。

使用return $! x 定义,上述表达式将导致未定义的异常。其值为 ⊥,不等于 42。

使用 (return $! x) >>= return 定义,它确实等于 42。

基本上return $! x形式在计算IO值的时候是严格的。另一种形式只有在运行 IO 值并使用该值时才严格(使用>>=)。

更多详情请见this mailing list thread

【讨论】:

  • 为什么(return $! undefined) >>= returnreturn $! undefined 不同?我的猜测是前者引入了一个额外的间接层,它可以防止undefined((return $! undefined) >>= return) `seq` 42 中被评估。
猜你喜欢
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 2016-06-28
相关资源
最近更新 更多