14

我只是写了一点代码,我想在 IO Monad 中使用保护功能。但是,对于 IO 没有 MonadPlus 的定义,这意味着我们不能在 IO 领域使用守卫。我已经看到了一个使用 MabyeT 转换器在 Maybe Monad 中使用警卫然后解除所有 IO 操作的示例,但如果我不需要,我真的不想这样做。

我想要的一些例子可能是:

handleFlags :: [Flag] -> IO ()
handleFlags flags = do
    when (Help `elem` flags) (putStrLn "Usage: program_name options...")
    guard (Help `elem` flags)
    ... do stuff ...
    return ()

我想知道是否有一种很好的方法可以通过 MonadPlus 的声明或其他方式在 IO Monad 中获取保护函数(或类似的东西)。或者我做错了;有没有更好的方法在上面的函数中编写帮助消息?谢谢。

(PS 我可以使用 if-then-else 语句,但它似乎以某种方式打破了这一点。更不用说对于很多选项它会导致大量的嵌套。)

4

3 回答 3

24

考虑 的定义MonadPlus

class Monad m => MonadPlus m where
    mzero :: m a 
    mplus :: m a -> m a -> m a

你将如何mzero实施IO?type 的值IO a表示返回某种类型的 IO 计算a,因此mzero必须是返回任何可能类型的某种 IO 计算。显然,没有办法为某个任意类型生成一个值,并且不像Maybe我们可以使用没有“空”构造函数,因此mzero必然代表一个永远不会返回的 IO 计算

你如何编写一个永远不会返回的 IO 计算?基本上,要么进入无限循环,要么抛出运行时错误。前者的效用令人怀疑,所以后者是你所坚持的。

简而言之,要MonadPlusIO你做的事情编写一个实例:mzero抛出一个运行时异常,并mplus在捕获由mzero. 如果没有引发异常,则返回结果。如果引发异常,则评估mplus的第二个参数,同时忽略异常。

也就是说,运行时异常通常被认为是不可取的,所以在走这条路之前我会犹豫不决。如果您确实想这样做(并且不介意增加程序在运行时崩溃的可能性),您将在Control.Exception.

在实践中,如果我想guard对评估单子表达式的结果进行大量分析,或者如果大多数条件依赖于作为函数参数提供的纯值(您示例中的标志是) 使用@Anthony 的回答中的模式防护。

于 2010-12-21T23:06:57.767 回答
8

我对守卫做这种事情。

handleFlags :: [Flag] -> IO ()
handleFlags flags
  | Help `elem` flags = putStrLn "Usage: program_name options..."
  | otherwise = return ()
于 2010-12-21T23:05:50.410 回答
0

有专门为此而设计的函数:在 Control.Monad 中,函数when及其对应的unless. 安东尼的回答可以改写成这样:

handleFlags :: [Flag] -> IO ()
handleFlags flags =
    when (Help `elem` flags) $ putStrLn "Usage: program_name options..."

规格:

when :: (Applicative m) => Bool -> m () -> m ()
unless bool = when (not bool)

链接到 hackage.haskell.org 上的文档

如果需要更多,这里是另一个包的链接,特别是面向 monad 和更多实用程序:Control.Monad.IfElse

于 2016-05-01T15:17:41.427 回答