Haskell IO的MonadPlus定义 [英] MonadPlus definition for Haskell IO

查看:102
本文介绍了Haskell IO的MonadPlus定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是写了一些代码,而且我想使用 guard function 。不过,没有定义用于IO的MonadPlus ,这意味着我们不能在IO域中使用警戒。我已经看到使用MabyeT转换器在Maybe Monad中使用警卫的例子然后解除所有的IO动作,但如果我不必这样做,我真的不想这么做。



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

pre code> handleFlags: :[标志] - > IO()
handleFlags flags =做
(帮助`elem`标志)(putStrLn用法:程序名称选项...)
guard(帮助`elem`标志)
...做东西...
return()

我想知道如果有是通过MonadPlus声明或其他方式在IO Monad中获得守卫功能(或类似功能)的好方法。或者我做错了;有没有更好的方法在上面的函数中写出帮助信息?谢谢。



(PS我可以使用if-then-else语句,但似乎以某种方式击败了这一点,更不用说对于很多选项,它会导致)

解决方案

考虑定义 MonadPlus

  class Monad m => MonadPlus m其中
mzero :: m a
mplus :: m a - > m a - > ma

你会如何实现 mzero code> IO ?类型 IO a 的值表示一个IO计算,它返回类型为 a 的东西,所以 mzero 必须是返回任何可能类型的IO计算。很明显,没有办法为某些任意类型创建一个值,而且与 Maybe 不同,我们可以使用没有空的构造函数,所以 mzero 必然代表一个永远不会返回的IO计算。



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



总之,要编写一个 MonadPlus code>对于 IO 你应该做的是这样的:让 mzero 抛出一个运行时异常, mplus 在捕获由 mzero 引发的任何异常时评估其第一个参数。如果没有发生异常,则返回结果。如果发生异常,请在忽略异常的情况下评估 mplus 的第二个参数。



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

实际上,如果我想要很多 guard

I was just writing a quick bit of code, and I wanted to use the guard function in the IO Monad. However, there is no definition of MonadPlus for IO which means that we cannot use guard in IO land. I have seen an example of using the MabyeT transformer to use guard in the Maybe Monad and then lifting all of the IO actions but I do not really want to do that if I do not have to.

Some example of what I want might be:

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

I was wondering if there was a nice way to get a guard function (or something similar) in the IO Monad through a declaration for MonadPlus or otherwise. Or perhaps I am doing it wrong; is there a better way to write that help message in the function above? Thanks.

(P.S. I could use if-then-else statements but it seems to defeat the point somehow. Not to mention that for a lot of options it will result in a huge amount of nesting.)

解决方案

Consider the definition of MonadPlus:

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

How would you implement mzero for IO? A value of type IO a represents an IO computation that returns something of type a, so mzero would have to be an IO computation returning something of any possible type. Clearly, there's no way to conjure up a value for some arbitrary type, and unlike Maybe there's no "empty" constructor we can use, so mzero would necessarily represent an IO computation that never returns.

How do you write an IO computation that never returns? Either go into an infinite loop or throw a runtime error, basically. The former is of dubious utility, so the latter is what you're stuck with.

In short, to write an instance of MonadPlus for IO what you'd do is this: Have mzero throw a runtime exception, and have mplus evaluate its first argument while catching any exceptions thrown by mzero. If no exceptions are raised, return the result. If an exception is raised, evaluate mplus's second argument instead while ignoring exceptions.

That said, runtime exceptions are often considered undesirable, so I'd hesitate before going down that path. If you do want to do it that way (and don't mind increasing the chance that your program may crash at runtime) you'll find everything you need to implement the above in Control.Exception.

In practice, I'd probably either use the monad transformer approach if I wanted a lot of guarding on the result of evaluating monadic expressions, or if most of the conditionals depend on pure values provided as function arguments (which the flags in your example are) use the pattern guards as in @Anthony's answer.

这篇关于Haskell IO的MonadPlus定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆