在IO中提取Maybe值

So8*_*res 15 io monads haskell maybe

鉴于以下内容:

> (liftM2 fromMaybe) (ioError $ userError "OOPS") (return $ Just "ok")
Run Code Online (Sandbox Code Playgroud)

ghci给了我

*** Exception: user error (OOPS)
Run Code Online (Sandbox Code Playgroud)

当然,来自Maybe的工作正常:

> (liftM2 fromMaybe) (return $ "not me") (return $ Just "ok")
"ok"
Run Code Online (Sandbox Code Playgroud)

但似乎IO操作正在执行然后被丢弃:

> (liftM2 fromMaybe) (putStrLn "computing.." >> "discarded") (return $ Just "ok")
computing..
"ok"
Run Code Online (Sandbox Code Playgroud)

为什么会这样?有没有什么方法可以让IO Monad更加懒散?

具体来说,考虑value :: IO (Maybe a)到(简洁,简洁)的说法

result <- (liftM2 fromMaybe) err value
Run Code Online (Sandbox Code Playgroud)

并解压缩结果或相应地抛出IOError?

Ant*_*ony 12

我不知道制作更IO懒的是这里正确的方向.你似乎想要做的是先了解Maybe,然后消除它.这可以用几种方式编写,这里有一个选项:

test :: IO (Maybe a) -> IO a
test = (>>= maybe (ioError $ userError "oops") return)
Run Code Online (Sandbox Code Playgroud)


ham*_*mar 10

如果你转换liftM2为do-notation,那么你的代码失败的原因很明显:

do x <- ioError $ userError "OOPS"
   y <- return $ Just "ok"
   return $ fromMaybe x y
Run Code Online (Sandbox Code Playgroud)

这永远不会超过第一行,因为它无条件地抛出异常.

安东尼的建议会很好,但如果你不关心抛出的特定异常,你也可以使用模式匹配:

do Just result <- value
Run Code Online (Sandbox Code Playgroud)

如果模式不匹配,则会调用fail,在IOmonad 的情况下抛出异常.

> Just x <- return Nothing
*** Exception: user error (Pattern match failure in do expression at <interactive>:1:0-5)
Run Code Online (Sandbox Code Playgroud)


Dan*_*ton 5

什么是(干净,简洁)的方式...解包[结果]或相应地抛出IOError?

我建议你不要依赖抛出错误.相反,明确处理"错误":

maybeM :: Monad m => m b -> (a -> m b) -> m (Maybe a) -> m b
maybeM err f value = do
  x <- value
  case x of
    Just y  -> f y
    Nothing -> err

-- This can be written simply as:
maybeM err f value = do
  x <- value
  maybe err f x

-- or even shorter! This is starting to look like Anthony's answer :)
maybeM err f value = value >>= maybe err f
Run Code Online (Sandbox Code Playgroud)

函数的输入和类型应该说明一切.您可以通过为Nothing案例执行操作来执行它,或者对Just案例内部的值执行函数.对于您的特定输入,这将看起来像:

maybeM (ioError $ userError "OOPS") return (return $ Just "ok")
Run Code Online (Sandbox Code Playgroud)

因此,如果你绝对必须,那么"解压缩结果或抛出IOError的简洁方法"将是:

-- compare to fromJust, a function to be avoided
fromJustIO :: IO (Maybe a) -> IO a
fromJustIO = maybeM (ioError $ userError "OOPS") return
Run Code Online (Sandbox Code Playgroud)

注意这个类型签名是如何实际的Maybe a -> a,这是本质上magicMonadUnwrap :: Monad m => m a -> a应该引发一些危险信号.但是,您可以以简单的方式使用此暴行:

result <- fromJustIO value
Run Code Online (Sandbox Code Playgroud)

虽然我再次强烈反对在这里使用例外.尝试以更简单的方式处理错误,而不仅仅是爆炸,通过使用maybeM并提供IO操作以在发生故障时执行.

  • So8res:我个人有第二层函数生成`Maybe`值,然后第一层配置函数可以将它们与`sequence`或`<$>`和`<*>`混为一谈,或根据需要单独处理每个潜在错误.这是一个品味的问题,但在我看来,错误在Haskell中几乎总是一个坏主意,因为我们有强大的抽象,让我们组成"可能".throw/catch控制流机制与Haskell鼓励的FP风格不匹配. (4认同)