基本上,我想要做的是手工定义
maybeCombine :: (a->a->a) -> Maybe a -> Maybe a -> Maybe a
maybeCombine _ Nothing Nothing = Nothing
maybeCombine _ (Just a) Nothing = Just a
maybeCombine _ Nothing (Just a) = Just a
maybeCombine f (Just a) (Just a') = Just $ f a a'
Run Code Online (Sandbox Code Playgroud)
在需要的时候在本地定义这个并不是什么大不了的事情,但仍然是笨拙的,并且如此基本和一般似乎应该有一个标准的实现,但我似乎找不到一个.
也许我只是忽略了一些东西.我想要的似乎与monad的行为完全无关,所以我认为我在Monad/Arrow抽屉里找不到任何东西; 但它确实类似于Monoid实例
Prelude Data.Monoid> Just"a"<> Nothing
Just"a"
Prelude Data.Monoid> Just"a"<> Just"b"
Just"ab"
......
...然而a,它本身需要一个幺半群,即它基本上具有a->a->a"内置".该MonadPlus实例的行为也很像我想要的,但它只是抛弃了其中一个值而不是允许我提供组合函数
Prelude Data.Monoid Control.Monad> Just 4`mplus` Nothing
Just 4
Prelude Data.Monoid Control.Monad> Nothing`mplus` Just 4
Just 4
Prelude Data.Monoid Control.Monad> Just 4`mplum` Just 5
Just 4
什么是规范解决方案?局部模式匹配?来自例如组合器的东西Data.Maybe?定义一个自定义的monoid进行组合?
Edw*_*ETT 12
你可以随时使用
f <$> m <*> n <|> m <|> n
Run Code Online (Sandbox Code Playgroud)
但遗憾的是,这在任何地方都没有规范的实施.
您可以使用reflection来获取(a -> a -> a)"烤"作为Semigroup与使用Option,这是由提供semigroups作为的改进版本Maybe是对"正确"的实例Monoid来讲Semigroup.尽管如此,这对于这个问题来说太过沉重.=)
也许这应该只是作为一个组合添加Data.Maybe.
J. *_*son 11
当你注意到它就f像是Monoid对基础a类型的操作时,你是对的.更具体地讲这是怎么回事的是你举起Semigroup成Monoid由相邻的零(mempty)Nothing.
这正是你在Haddocks中看到的Maybe Monoid实际情况.
根据http://en.wikipedia.org/wiki/Monoid将半群提升为Maybe形成一个Monoid :"任何半群S可以简单地通过邻接不在S中的元素e并定义e e = e而变成一个monoid.所有s∈S的e s = s = s*e" 由于没有提供mappend的"Semigroup"类型类,我们使用Monoid代替.
或者,如果你喜欢这个semigroups包,那么就有Option这种行为,适当地推广使用底层Semigroup代替.
因此,这表明最明确的方法是在底层类型上定义一个Monoid或一个Semigroup实例a.将一些组合器f与该类型相关联是一种干净的方法.
如果你不控制那种类型,不想要孤立实例,并认为newtype包装器很难看怎么办?通常你会失去运气,但这是一个使用全黑魔法的地方,有效的GHC专用reflection包装就派上用场了.本文中有完整的解释,但Ausin Seipp的FP完整教程包含一些示例代码,允许您将任意半群产品"注入"到没有(尽可能多)类型定义噪声的类型中,代价是更加可怕的签名.
然而,这可能比它的价值明显更多.