处理Maybe Bool值

时间:2013-12-09 12:09:45

标签: haskell monads maybe

我们说,我有两个Maybe Bool值,我希望实现以下功能:

  • 如果两者都是Just值,我想在它们之间执行||值。
  • 如果其中一个是Nothing而另一个是Just值,那么我希望Just值作为输出。
  • 如果两者都是Nothing,那么我希望Just False作为输出。

我知道这可以通过模式匹配来实现。但是可以使用任何monadic函数来实现结果吗?

liftM2适用于此案例:

ghci> liftM2 (||) (Just True) (Just False)
Just True

但是当{1}}中的任何一个输入为liftM2时,Nothing将生成Nothing(我想要其他Just值)。即:

ghci> liftM2 (||) (Nothing) (Just False)
Nothing

但在上述情况下我想要Just False

是否可以使用任何monadic函数执行此操作?

3 个答案:

答案 0 :(得分:9)

就目前而言,我们甚至不需要调用monadic设备。根据您的规范,“Nothing”可以映射到“False”,“Just b”映射到“b”:

mbor a b = Just (flat a || flat b)
   where flat = maybe False id

正如@leftaroundabout正确地指出这基本上是Monoid Any实例所做的。

答案 1 :(得分:6)

此处非常有用的运算符来自<|>Alternative类的Control.Applicative。对于Maybe,它的工作原理如下:

Just a  <|> _       = Just a
Nothing <|> Just a  = Just a
Nothing <|> Nothing = Nothing

我们还可以利用x || x == x始终为真的事实。这让我们写下以下内容:

orMaybe a b = liftA2 (||) (a <|> b) (b <|> a) <|> Just False

如果ab都是Just x,则liftA2 (||)会生成Just (a || b)。如果其中一个为Nothing,则(a <|> b)(b <|> a)会同时变为a或同时变为b,从而产生Just (a || a)或{{ 1}}。最后,如果两者都是Just (b || b),我们会得到Nothing,这会导致liftA2 (||) Nothing Nothing。最终Nothing然后将整个表达式转换为<|> Just False

现在,我认为这是一项有趣的练习。但我真的会使用这段代码吗? !对于Just FalseMaybe通常表示失败并传播;因为你正在使用一些非标准的行为,所以最好是明确地将所有情况与模式匹配。

注意:Nothing来自liftA2。它就像Control.Applicative但是对于应用程序而言;我用它来与liftM保持一致。您也可以使用<|>

答案 2 :(得分:6)

没有。 monad实例没有空虚概念 1 ,因此无法检查Nothing并替换该情况下的值。

你基本上需要的是 monoid 实例;将Nothing作为其标识元素的内容,因此无论您与Nothing合并的是什么,都会以的形式出现

instance (Monoid a) => Monoid (Maybe a)

不幸的是,Bool本身并不是幺半群。嗯,实际上它是一个幺半群!但不是以一种独特的方式,所以他们无法选择任何特定的实例。但是使用newtype包装器,它们位于Data.Monoid

newtype Any = Any { getAny :: Bool }
instance Monoid Any

让我们试试吧......

  

Prelude Data.Monoid&gt; fmap getAny $(只是$ Any True)&lt;&gt; (只是$ Any False)
  刚才   Prelude Data.Monoid&gt; fmap getAny $(Nothing)&lt;&gt; (只是$ Any False)
  只是错误


1 当然,有fail ......但这是一次历史性事故。