gpt4 book ai didi

haskell - 为什么 Haskell 异常只能在 IO monad 中捕获?

转载 作者:行者123 更新时间:2023-12-03 09:58:11 25 4
gpt4 key购买 nike

谁能解释为什么异常可能会在 IO monad 之外抛出,但只能在其中捕获?

最佳答案

原因之一是 denotational semantics of Haskell .

(纯)Haskell 函数的简洁属性之一是它们的单调性——更多定义的参数会产生更多定义的值。这个属性非常重要,例如推理递归函数(阅读文章以了解原因)。

定义异常的表示是底部,_|_ ,与给定类型相对应的poset中的最小元素。因此,为了满足单调性要求,以下不等式需要对任何表示 f 成立。 Haskell 函数:

f(_|_) <= f(X)

现在,如果我们可以捕获异常,我们可以通过“识别”底部(捕获异常)并返回更多定义的值来打破这种不等式:
f x = case catch (seq x True) (\exception -> False) of
True -> -- there was no exception
undefined
False -> -- there was an exception, return defined value
42

这是完整的工作演示(需要 base-4 Control.Exception):
import Prelude hiding (catch)
import System.IO.Unsafe (unsafePerformIO)
import qualified Control.Exception as E

catch :: a -> (E.SomeException -> a) -> a
catch x h = unsafePerformIO $ E.catch (return $! x) (return . h)

f x = case catch (seq x True) (\exception -> False) of
True -> -- there was no exception
undefined
False -> -- there was an exception, return defined value
42

正如 TomMD 所指出的,另一个原因是破坏了引用透明度。您可以用相等替换相等的东西并得到另一个答案。 (在指称意义上相等,即它们表示相同的值,而不是在 == 意义上。)

我们将如何做到这一点?考虑以下表达式:
let x = x in x

这是一个非终止递归,所以它从不返回任何信息,因此也用 _|_ 表示。 .如果我们能够捕获异常,我们可以编写函数 f,例如
f undefined = 0
f (let x = x in x) = _|_

(对于严格的函数,后者总是正确的,因为 Haskell 没有提供检测非终止计算的方法——而且原则上也不能,因为 Halting problem 。)

关于haskell - 为什么 Haskell 异常只能在 IO monad 中捕获?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3642793/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com