如何使用may monoid并将值与自定义操作相结合?

lef*_*out 11 haskell monoids

基本上,我想要做的是手工定义

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类型的操作时,你是对的.更具体地讲这是怎么回事的是你举起SemigroupMonoid由相邻的零(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完整教程包含一些示例代码,允许您将任意半群产品"注入"到没有(尽可能多)类型定义噪声的类型中,代价是更加可怕的签名. 

然而,这可能比它的价值明显更多.

  • 真棒!我经常最终将"Option(Max a)"定义为一个类型的"负无穷大",绝对是.我认为这是一个非常优雅的"Monoid". (3认同)