Haskell IO的MonadPlus定义

Rob*_*oli 13 io monads haskell guard

我只是写了一小段代码,我想在IO Monad中使用guard功能.但是,没有MonadPlus for IO的定义,这意味着我们不能在IO 域中使用guard.我已经看到了使用MabyeT变换器在Maybe Monad中使用guard然后解除所有IO操作的示例,但如果我不需要,我真的不想这样做.

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

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

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

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

C. *_*ann 23

考虑以下定义MonadPlus:

class Monad m => MonadPlus m where
    mzero :: m a 
    mplus :: m a -> m a -> m a
Run Code Online (Sandbox Code Playgroud)

你将如何实现mzeroIO?类型的值IO a表示返回类型的IO计算a,因此mzero必须是返回任何可能类型的IO计算.显然,没有办法变出一些任意类型的值,而不像Maybe有没有"空"构造,我们可以使用,这样mzero一定代表永远不会返回一个IO计算.

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

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

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

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

  • @Robert Massaioli:这并不是说这有什么“错误”。这是一个完全正确的 `MonadPlus` 实例,它相当于 `MonadPlus` 使用 `Either e` 作为错误 monad 的方式,我认为这样的 `IO` 实例甚至存在于一个 monad 转换器库中。唯一的问题是你必须更加小心地捕获错误,因为与“MaybeT”等不同,异常可以一直逃逸到“main”。 (2认同)

Ant*_*ony 8

我和守卫一起做这件事.

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

  • 有时候你知道你是在正确的轨道上(使用警卫)但是有人指出了正确的想法(这个)并且你有一个额头拍打时刻.谢谢,我用过这个,这正是我想要的.虽然我把camccann标记为答案,因为他说明了为什么我的想法很糟糕,我的选择是什么,然后指出你的想法是他本来会做的. (2认同)