"evaluate" 和 "return $!" 有什么区别?(涉及 IT 技术)

23
以下是evaluate文档的摘录:

在这里,我们提供了evaluate的一部分文档:

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

is not the same as

return $! x

A correct definition is

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

(source)

这两个定义似乎有相同的意思。它们之间有什么区别?


5
这实际上不违反单子定律吗? - leftaroundabout
3
不,它们不一样。如果运行它们,两者的行为完全相同,但如果你对这些表达式进行seq操作,return $! x具有最外层的seq,而(return $! x) >>= return则具有最外层的(>>=) - Daniel Fischer
4
不可以,因为 ⊥ 在法则中被忽略。标准单子(例如 Reader)的行为方式也是如此。我不同意 Daniel Fischer 的观点(我之前从其他人那里听过),因为“如果运行时完全相同的行为”并不是一个明确定义的概念。 - ehird
@DanielFischer 我不确定你的说法是否正确。\seq`的优先级低于>>=->>=`怎么可能是最外层的? - mucaho
2
@mucaho,我所说的是将成为seq参数的两个表达式。在seq (return $! x)中,return $! x具有最外层的seq(来自$!),而在seq ((return $! x) >>= return)中,(return $! x) >>= return具有最外层的>>= - Daniel Fischer
1个回答

21

快速参考:

evaluate 的类型为:

evaluate :: a -> IO a

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

以下是 evaluate 遵循的三条规则:

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值被运行并且使用值(使用 >>=)时才是严格的。

有关更多详情,请参见此邮件列表线程


为什么(return $! undefined) >>= returnreturn $! undefined不同?我猜测前者引入了一个额外的间接层,防止在((return $! undefined) >>= return) \seq` 42中评估undefined`。 - mucaho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接