[英]Why is Maybe's Semigroup instance biased towards Just and the Monoid uses Nothing as its empty element?
Maybe
表示可能由於錯誤而不會產生結果的計算。 因此,這種計算必須短路。
現在, Maybe
的Semigroup / Monoid實例似乎打破了這種語義,因為前者偏向於Just
而后者將錯誤情況視為Nothing
作為其空元素:
Just "foo" <> Nothing -- Just "foo"
Nothing <> Just "bar" -- Just "bar"
Just "foo" <> Just "bar" -- Just "foobar"
Nothing <> Nothing -- Nothing
對於前兩種情況,我希望Nothing
。
這是替代實現(希望它是正確/合法的):
instance Semigroup a => Semigroup (Maybe a) where
Nothing <> _ = Nothing
_ <> Nothing = Nothing
Just a <> Just b = Just (a <> b)
instance Monoid a => Monoid (Maybe a) where
mempty = Just mempty
我不想說這些替代實例更好。 但它們似乎也很有用。 那么為什么首先進行選擇而不是將實現留給用戶呢?
您的實例實際上是應用函子的更通用實例的特例。
newtype LiftA f a = LiftA { getLiftA :: f a }
instance (Applicative f, Semigroup a) => Semigroup (LiftA f a) where
LiftA x <> LiftA y = LiftA $ liftA2 (<>) x y
instance (Applicative f, Monoid a) => Monoid (LiftA f a) where
mempty = LiftA $ pure mempty
我認為它會在某個地方的標准庫中(可能在不同的名稱下),但我找不到它。 但是這個一般實例的存在可能是選擇Maybe
的庫版本的一個原因,這更像是Maybe
的特殊能力。 另一方面,當你的代數結構彼此連貫時,它是相當不錯的; 即當一個類型是Applicative
時,盡可能使用“ LiftA
”式實例(在所有F代數類上)。
在第三方面(!),我們無法在任何地方保持一致性,因為庫實例與Maybe
的MonadPlus
實例一致。 這與自然數上存在兩個幺半群的事實驚人地相似:加法和乘法。 對於數字,我們選擇不要有任何 monoid實例,因為它不清楚使用哪個。
總之,我不知道。 但也許這些信息很有幫助。
我認為這背后的想法是, Maybe
應該具有實際上只有Option
正確表達的語義:它需要任何半群並通過添加Nothing
作為臨時“免費mempty”而使其成為monoid。 即實際上應該是實例
instance Semigroup a => Semigroup (Maybe a) where
Nothing <> a = a
a <> Nothing = a
Just x <> Just y = Just $ x <> y
instance Semigroup a => Monoid (Maybe a) where
mappend = (<>)
mempty = Nothing
這類似於[]
通過添加mempty
和<>
給出任何類型的自由monoid。
當然,這要求Semigroup
類在base
,直到最近才出現。
對此的推論是, mempty
變得明顯模式匹配,因為通過參數化它不能依賴於包含的類型。
實際上,這個實例可能比你提出的實例更有用,因為正如Luke所說, Applicative
實例已經涵蓋了這個實例,所以你可以輕松編寫liftA2 (<>)
和pure mempty
。 當然,標准實例也已經被Alternative
實例所覆蓋,但是Alternative/MonadPlus
一直被認為有點hackish,不如數學上無可挑剔的Semigroup
, Monoid
, Functor
和Applicative
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.