gpt4 book ai didi

haskell - 为什么 throw 和 throwIO 有区别?

转载 作者:行者123 更新时间:2023-12-04 16:42:04 27 4
gpt4 key购买 nike

我试图牢牢掌握异常情况,以便改进我的conditional loop implementation .为此,我进行了各种实验,扔东西,看看会被抓到什么。

这个让我惊喜不已:

% cat X.hs
module Main where

import Control.Exception
import Control.Applicative

main = do
throw (userError "I am an IO error.") <|> print "Odd error ignored."
% ghc X.hs && ./X
...
X: user error (I am an IO error.)
% cat Y.hs
module Main where

import Control.Exception
import Control.Applicative

main = do
throwIO (userError "I am an IO error.") <|> print "Odd error ignored."
% ghc Y.hs && ./Y
...
"Odd error ignored."

我认为替代方案应该完全忽略 IO 错误。 (不知道我从哪里得到这个想法,但我当然不能提供一个在替代链中会被忽略的非 IO 异常。)所以我想我可以手工制作并提供一个 IO 错误。事实证明,它是否被忽略取决于包装和内容:如果我 throw一个 IO 错误,不知何故不再是一个 IO 错误。

我完全迷路了。为什么它会这样工作?是有意的吗?这些定义深入到 GHC 内部模块;虽然我自己或多或少可以理解不同代码片段的含义,但我很难看到整个画面。

如果很难预测,甚至应该使用这个替代实例吗?如果它消除任何同步异常,而不仅仅是以特定方式定义并以特定方式抛出的一小部分异常,这不是更好吗?

最佳答案

throwundefined 的概括和 error ,这意味着在纯代码中抛出异常。当异常的值无关紧要时(大多数情况下),它用符号 ⟘ 表示“未定义值”。
throwIO是一个抛出异常的 IO Action ,但它本身并不是一个未定义的值。

throwIO 的文档因此说明了差异:

throw e   `seq` x  ===> throw e
throwIO e `seq` x ===> x

问题是 (<|>)定义为 mplusIO 它使用 catchException 这是 catch 的严格变体.这种严格性总结如下:
⟘ <|> x = ⟘

因此在 x 中出现异常(并且 throw 永远不会运行)变体。

请注意,如果没有严格性,“未定义的 Action ”(即 throw ... :: IO a )实际上表现得就像从 catch 的角度抛出的 Action 。 :
catch (throw   (userError "oops")) (\(e :: SomeException) -> putStrLn "caught")  -- caught
catch (throwIO (userError "oops")) (\(e :: SomeException) -> putStrLn "caught") -- caught
catch (pure (error "oops")) (\(e :: SomeException) -> putStrLn "caught") -- not caught

关于haskell - 为什么 throw 和 throwIO 有区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57401539/

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