我想做的事情是手工定义,基本上是
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'
这对define this locally when needed来说并不是什么大不了的事,但仍然是笨拙的,并且如此基本和普遍,似乎应该有一个标准的实现,但我似乎找不到一个。
也许我只是忽略了一些东西。我想要的似乎与monad的行为完全无关,所以我认为我在Monad / Arrow抽屉里找不到任何东西;但它确实类似于Monoid
实例
Prelude Data.Monoid>只是“一个”<>没有
只是“一个”
Prelude Data.Monoid>只是“一个”<>只是“b”
只是“ab”
...
...但是要求a
本身就是一个幺半群,即它基本上有a->a->a
“内置”。 MonadPlus
实例的行为也很像我想要的,但它只是抛弃了其中一个值而不是允许我提供组合函数
Prelude Data.Monoid Control.Monad>只是4` mplus`什么都没有 只是4
Prelude Data.Monoid Control.Monad>没什么`mplus`只是4
只是4
Prelude Data.Monoid Control.Monad>只需4` mplus`只需5 仅4岁
规范解决方案是什么?本地模式匹配?用例如组合器的东西Data.Maybe
?定义一个自定义的monoid进行组合?
答案 0 :(得分:12)
您可以随时使用
f <$> m <*> n <|> m <|> n
但遗憾的是,这在任何地方都没有规范的实施。
您可以使用reflection
将“{1}}”作为(a -> a -> a)
加入Semigroup
,与Option
一起使用semigroups
作为Maybe
的改进版本,Monoid
具有Semigroup
的“正确”实例。尽管如此,这对于这个问题来说太过沉重。 =)
也许这应该作为组合添加到Data.Maybe
。
答案 1 :(得分:11)
如果您发现f
与基础Monoid
类型的a
操作类似,那么您就是对的。更具体地说,这里发生的事情是,您将Semigroup
提升为Monoid
,与零(mempty
),Nothing
相邻。
这正是你在Haddocks中实际看到的Maybe
Monoid
。
根据http://en.wikipedia.org/wiki/Monoid将半群提升为可能形成一个幺半群:“任何半群S可以简单地通过邻接不在S中的元素e并且定义e e = e和e <而变成幺半群所有s∈S的/ em> s = s = s * e“由于没有提供mappend的“Semigroup”类型类,我们使用Monoid代替。
或者,如果你喜欢semigroups
软件包,那么Option
就会出现这种行为,适当地推广使用基础Semigroup
。
因此,这表明最明确的方法是在基础类型Monoid
上定义Semigroup
或a
实例。将一些组合器f
与该类型相关联是一种干净的方法。
如果您不控制该类型,不想要孤立实例,并认为newtype
包装器难看,该怎么办?通常情况下你运气不好,但这是一个使用全黑魔法的地方,有效的GHC专用reflection
包就派上用场了。存在彻底的解释in the paper itself但是Ausin Seipp's FP Complete Tutorial包括一些示例代码,允许您将任意半群产品“注入”到没有(尽可能多)类型定义噪声的类型中......代价是更加可怕的签名。
然而,这可能比它的价值要大得多。
答案 2 :(得分:2)
import Data.Monoid
maybeCombine :: (a->a->a) -> Maybe a -> Maybe a -> Maybe a
maybeCombine f mx my = let combine = mx >>= (\x -> my >>= (\y -> Just (f x y)))
in getFirst $ First combine `mappend` First mx `mappend` First` my
在GHCi中,这给了我
*Main> maybeCombine (+) Nothing Nothing
Nothing
*Main> maybeCombine (+) (Just 3) Nothing
Just 3
*Main> maybeCombine (+) (Just 3) (Just 5)
Just 8
如果您将getLast
放在Last combine
序列的末尾
mappend