Haskell IO的MonadPlus定义

时间:2010-12-21 22:18:42

标签: haskell io monads guard

我只是写了一小段代码,我想在IO Monad中使用guard function。但是,有no definition of MonadPlus for IO这意味着我们不能在IO土地上使用守卫。我已经看过an example of using the MabyeT transformer to use guard in the 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中获得一个保护功能(或类似的东西)。或许我做错了;有没有更好的方法在上面的函数中编写帮助消息?感谢。

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

3 个答案:

答案 0 :(得分:22)

考虑MonadPlus

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

您如何为mzero实施IO?类型IO a的值表示返回类型a的IO计算,因此mzero必须是IO计算,返回任何可能类型的内容。显然,没有办法为某些任意类型设置一个值,并且与Maybe不同,我们可以使用没有“空”的构造函数,因此{em}必然代表一个永不返回的IO计算

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

简而言之,要为mzero编写MonadPlus的实例,您要做的是:让IO抛出运行时异常,并mzero评估其捕获mplus抛出的任何异常时的第一个参数。如果没有引发异常,则返回结果。如果引发异常,请在忽略异常时评估mzero的第二个参数。

也就是说,运行时异常通常被认为是不合需要的,所以在走这条路之前我会犹豫不决。如果您确实希望这样做(并且不介意增加程序在运行时崩溃的可能性),您将在mplus中找到实现上述所需的一切。

在实践中,如果我想要评估monadic表达式的结果有很多Control.Exception,或者大多数条件依赖于作为函数参数提供的纯值,我可能要么使用monad变换器方法(在你的例子中的标志是)使用模式守卫,如@ Anthony的答案。

答案 1 :(得分:8)

我和警卫一起做这件事。

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

答案 2 :(得分: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)

Link to docs on hackage.haskell.org

如果需要更多内容,请点击link to another package, specifically monad-oriented and with several more utilities: Control.Monad.IfElse