提取 IO 中的 Maybe 值
鉴于以下内容:
> (liftM2 fromMaybe) (ioError $ userError "OOPS") (return $ Just "ok")
ghci 给了我
*** Exception: user error (OOPS)
当然,fromMaybe 工作正常:
> (liftM2 fromMaybe) (return $ "not me") (return $ Just "ok")
"ok"
但似乎 IO 操作正在执行,然后被丢弃:
> (liftM2 fromMaybe) (putStrLn "computing.." >> "discarded") (return $ Just "ok")
computing..
"ok"
为什么会发生这种情况?有没有办法让 IO monad 变得更懒惰?
具体来说,给定 value :: IO (Maybe a) 什么是(干净、简洁)的表达方式
result <- (liftM2 fromMaybe) err value
并让它解压结果或相应地抛出 IOError ?
Given the following:
> (liftM2 fromMaybe) (ioError $ userError "OOPS") (return $ Just "ok")
ghci gives me
*** Exception: user error (OOPS)
Of course, fromMaybe is working correctly:
> (liftM2 fromMaybe) (return $ "not me") (return $ Just "ok")
"ok"
But it seems that the IO operation is being carried out and then discarded:
> (liftM2 fromMaybe) (putStrLn "computing.." >> "discarded") (return $ Just "ok")
computing..
"ok"
Why is this happening? Is there any way to make the IO monad lazier?
Specifically, given value :: IO (Maybe a)
what's a (clean, concise) way to say
result <- (liftM2 fromMaybe) err value
and have it unpack result or throw an IOError accordingly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不知道让 IO 更懒惰是正确的方向。您似乎想做的是首先找到“也许”,然后消除它。这可以用多种方式编写,这是一种选择:
I don't know that making
IO
lazier is the right direction here. What you seem to want to do is first get at theMaybe
, then eliminate it. This can be written several ways, here's one option:如果您从
liftM2
转换为 do-notation,很明显您的代码失败的原因:这永远不会超过第一行,因为它无条件抛出异常。
Anthony的建议可以正常工作,但是如果你不关心抛出的具体异常,你也可以使用模式匹配:
如果模式不匹配,则会调用
fail
,在IO
monad 的情况下会引发异常。If you translate from
liftM2
to do-notation, it's obvious why your code fails:This will never go past the first line, as it's unconditionally throwing an exception.
Anthony's suggestion will work fine, but if you don't care about the specific exception thrown, you can also use pattern matching:
If the pattern doesn't match, this will call
fail
, which in the case of theIO
monad throws an exception.我建议您避免依赖抛出错误。相反,明确地处理“错误”:
函数的输入和类型应该不言而喻。您可以通过给它一个在
Nothing
情况下执行的操作,或在Just
情况下对内部值执行的函数来使用它。对于您的特定输入,这看起来像:因此,如果您绝对必须,那么“解压结果或抛出 IOError 的简洁方法”将是:
请注意,其类型签名实际上是
也许-> a
,这是magicMonadUnwrap :: Monad m => 的本质妈-> a
,这应该会引发一些危险信号。然而,您可以通过简单的方式使用这种暴行:尽管如此,我再次强烈反对在这里使用异常。尝试以比简单爆炸更优雅的方式处理错误,方法是使用 MaybeM 并提供在失败时执行的 IO 操作。
I recommend you avoid relying on throwing errors. Instead, handle the "error" explicitly:
The function's inputs and types should speak for themselves. You use it by giving it an action to perform for the
Nothing
case, or a function to perform on the value inside for theJust
case. For your particular inputs this would look like:So if you absolutely must, then the "concise way to unpack the result or throw an IOError" would be:
Notice how the type signature for this is practically
Maybe a -> a
, which is the essence ofmagicMonadUnwrap :: Monad m => m a -> a
, which should set off some red flags. However, you can use this atrocity in a simple manner:Although again, I strongly discourage the use of exceptions here. Try handling errors in a more elegant way than simply exploding, by using
maybeM
and providing an IO action to execute in the event of failure.