2010-12-21 48 views
10

我刚写了一段代码,我想在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操作,但是如果我不必这样做,我真的不想这么做。Haskell IO的MonadPlus定义

什么,我想可能是一些例子:

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

我在想,如果有一个很好的方式获得通过的MonadPlus或以其他方式声明的保护功能(或类似的东西)的IO单子。或者我做错了;有没有更好的方法在上面的函数中写出帮助信息?谢谢。

(PS我可以使用的if-then-else语句,但它似乎以某种方式击败的地步。更何况,对于很多的选项时,它会造成巨大的嵌套的量。)

回答

20

考虑的MonadPlus定义:

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

你将如何实现mzeroIOIO a类型的值代表返回某种类型a的IO计算,因此mzero必须是返回某种可能类型的IO计算。显然,没有办法为某些任意类型设想一个值,而不像Maybe那里没有我们可以使用的“空”构造函数,所以mzero必然表示IO计算永远不会返回

如何编写永不返回的IO计算?基本上,无论是进入无限循环还是抛出运行时错误。前者是可疑的实用程序,所以后者就是你坚持的东西。

总之,写的MonadPlus一个实例IO你会做是这样的:有mzero抛出一个运行时异常,并有mplus评价其第一个参数,而捉由mzero引发的任何异常。如果没有发生异常,则返回结果。如果发生异常,则可以在忽略异常的情况下评估mplus的第二个参数。

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

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

8

我做这类有警卫的事情。

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

有时候,你知道,你是正确的跟踪(使用警卫),但随后有人指出正确的想法(这个),你有一个额头拍打时刻。谢谢,我用这个,这正是我想要的。虽然我将camccann标记为答案,因为他向我展示了我的想法不好,我的选择是什么,然后指出你的做法。 – 2010-12-22 00:00:25

+1

请注意,像cmdargs这样的库可以为你处理这些东西:) – 2010-12-22 00:30:41

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