我们说,我有两个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函数执行此操作?
答案 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
如果a
和b
都是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 False
,Maybe
通常表示失败并传播;因为你正在使用一些非标准的行为,所以最好是明确地将所有情况与模式匹配。
注意: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
......但这是一次历史性事故。