Sib*_*ibi 5 monads haskell maybe
让我们说,我有两个Maybe Bool值,我想实现以下功能:
Just值,我想||在它们之间执行值.Nothing一个是Just值而另一个是值,那么我希望将Just值作为输出.Nothing,那么我想Just False作为输出.我知道这可以通过模式匹配来实现.但是可以使用任何monadic函数来实现结果吗?
liftM2 适用于这种情况:
ghci> liftM2 (||) (Just True) (Just False)
Just True
Run Code Online (Sandbox Code Playgroud)
但是当一个输入中的任何一个输入时(我想要其他值)liftM2将产生.即:NothingNothingJust
ghci> liftM2 (||) (Nothing) (Just False)
Nothing
Run Code Online (Sandbox Code Playgroud)
但我想Just False在上述情况下.
是否可以使用任何monadic函数执行此操作?
就目前而言,我们甚至不需要调用monadic设备.根据您的规范,"Nothing"可以映射到"False"和"Just b"到"b":
mbor a b = Just (flat a || flat b)
where flat = maybe False id
Run Code Online (Sandbox Code Playgroud)
正如@leftaroundabout正确地指出这基本上是Monoid Any实例所做的.
这里一个非常有用的操作员是<|>来自Alternative班级Control.Applicative.因为Maybe,它的工作原理如下:
Just a <|> _ = Just a
Nothing <|> Just a = Just a
Nothing <|> Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)
我们也可以利用x || x == x始终如一的事实.这让我们写下以下内容:
orMaybe a b = liftA2 (||) (a <|> b) (b <|> a) <|> Just False
Run Code Online (Sandbox Code Playgroud)
如果这两个a和b是Just x时,liftA2 (||)在结果Just (a || b).如果他们中的一个是Nothing,(a <|> b)并且(b <|> a)变成两者a或两者b,导致Just (a || a)或Just (b || b).最后,如果两者都是Nothing,我们得到的liftA2 (||) Nothing Nothing结果Nothing.然后决赛<|> Just False将整个表达式转化为Just False.
现在,我认为这是一项有趣的练习.但我真的会使用这段代码吗?不!因为Maybe,Nothing通常表示失败并传播; 因为你正在使用一些非标准的行为,所以最好是明确地将所有情况与模式匹配.
注意:liftA2来自Control.Applicative.它就像liftM申请人一样; 我用它来保持一致性<|>.你也可以使用fmap它.
不.monad实例没有空虚1的概念,因此Nothing在这种情况下它无法检查和替换值.
你基本上需要的是monoid实例; 它具有Nothing身份元素,所以无论你结合什么,Nothing都会按原样出来.
instance (Monoid a) => Monoid (Maybe a)
Run Code Online (Sandbox Code Playgroud)
不幸的Bool是,它本身并不是一个幺半群.嗯,实际上它是一个幺半群!但不是以一种独特的方式,所以他们无法选择任何特定的实例.但是有了newtype包装,那些包括Data.Monoid:
newtype Any = Any { getAny :: Bool }
instance Monoid Any
Run Code Online (Sandbox Code Playgroud)
我们来试试吧......
Prelude Data.Monoid> fmap getAny $(只要$ Any True)<>(只要$ Any False)
Just True
Prelude Data.Monoid> fmap getAny $(Nothing)<>(只要$ Any False)
只是假
1当然,有fail...但这是一次历史性事故.