[英]How to use the maybe monoid and combine values with a custom operation, easily?
基本上,我想要做的是手工定義
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'
在需要的時候在本地定義它並不是什么大不了的事,但仍然是笨拙的,並且如此基本和一般似乎應該有一個標准的實現,但我似乎找不到一個。
也許我只是忽略了一些東西。 我想要的似乎與monad的行為完全無關,所以我認為我在Monad / Arrow抽屜里找不到任何東西; 但它確實類似於Monoid
實例
Prelude Data.Monoid>只是“a”<>沒什么
只是“一個”
Prelude Data.Monoid>只是“a”<>只是“b”
只是“ab”
...
...然而,它需要a
幺半群本身,即它基本上具有a->a->a
“內置”。 MonadPlus
實例的行為也很像我想要的,但它只是拋棄了其中一個值而不是允許我提供組合函數
Prelude Data.Monoid Control.Monad> Just 4`mplus`沒什么
只是4
Prelude Data.Monoid Control.Monad>沒什么`mplus`只是4
只是4
Prelude Data.Monoid Control.Monad> Just 4`mplus`只需5
只是4
什么是規范解決方案? 局部模式匹配? 使用例如Data.Maybe
組合器的東西? 定義一個自定義的monoid進行組合?
你可以隨時使用
f <$> m <*> n <|> m <|> n
但遺憾的是,這在任何地方都沒有規范的實施。
您可以使用reflection
將(a -> a -> a)
“烘焙”作為Semigroup
與Option
一起使用,它由semigroups
提供,作為Maybe
的改進版本,具有Monoid
的“正確”實例Semigroup
。 盡管如此,這對於這個問題來說太過沉重。 =)
也許這應該只是作為Data.Maybe
的組合子Data.Maybe
。
當你注意到你是正確的金錢f
就像是一個Monoid
上的基本操作a
類型。 更具體地說,這里發生的是你通過連接零( mempty
), Nothing
將Semigroup
提升為Monoid
。
這正是你在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
。
因此,這表明最明確的方法是在底層類型a
上定義Monoid
或Semigroup
實例。 將一些組合器f
與該類型相關聯是一種干凈的方法。
如果你不控制那種類型,不想要孤立實例,並認為newtype
包裝器是丑陋的怎么辦? 通常你會失去運氣,但這是一個使用全黑魔法的地方,有效的GHC reflection
包就派上用場了。 本文中有 完整的解釋,但Ausin Seipp的FP完整教程包含一些示例代碼,允許您將任意半群產品“注入”到沒有(盡可能多)類型定義噪聲的類型中,代價是更加可怕的簽名。
然而,這可能比它的價值明顯更多。
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
如果將Last combine
放在mappend
序列的末尾,也可以使用getLast
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.