我只是写了一小段代码,我想在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语句,但它似乎以某种方式打败了这一点。更不用说对于很多选项它会导致大量的嵌套。)
答案 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