![](/img/trans.png)
[英]Why there isn't a Functor instance for Kleisli in Control.Arrow?
[英]Why isn't Kleisli an instance of Monoid?
如果你想附加兩個類型為(a - > mb)的函數,這樣你只能得到一個相同類型的函數來追加兩個結果,你可以使用Kleisli來做到這一點:
instance (Monad m, Monoid b) => Monoid (Kleisli m a b) where
mempty = Kleisli (\_ -> return mempty)
mappend k1 k2 =
Kleisli g
where
g x = do
r1 <- runKleisli k1 x
r2 <- runKleisli k2 x
return (r1 <> r2)
但是,目前Control.Arrow
沒有定義此類實例。 通常,在Haskell,我懷疑有一個很好的理由,但找不到哪一個。
這個問題是相當類似, 這一個 。 但是,使用Monoid我沒有看到定義實例的方法,例如:
instance (Monad m, Monoid b) => Monoid (a -> m b) where
[...]
因為已經存在一個實例:
instance Monoid b => Monoid (a -> b) where
[...]
在圖書館設計業務中,我們在這里面臨一個選擇點,我們選擇在集體政策(或缺乏集體政策)中不完全一致。
Monad
(或Applicative
)類型構造函數的Monoid
實例可以以多種方式出現。 逐點提升始終可用,但我們沒有定義
instance (Applicative f, Monoid x) => Monoid (f x) {- not really -} where
mempty = pure mempty
mappend fa fb = mappend <$> fa <*> fb
請注意, instance Monoid (a -> b)
就是這樣一個逐點提升,因此只要mb
的monoid實例為b
上的monoid逐點提升,就會發生(a -> mb)
逐點提升。
我們一般不進行逐點提升,不僅因為它會阻止其載體碰巧應用類型的其他Monoid
實例,而且因為f
的結構通常被認為比x
的結構更重要。 一個關鍵的例子是自由幺半群,更好地稱為[x]
,它是[]
和(++)
的Monoid
,而不是逐點提升。 幺半群結構來自列表包裝,而不是來自包裝的元素。
我的首選經驗法確實優先考慮類型構造函數中固有的幺半群結構優先於點式提升,或類型的特定實例的幺半群結構,如a -> a
的組合monoid。 這些可以並且確實得到newtype
包裝。
關於Monoid (mx)
是否應該與MonadPlus m
同時存在(和Alternative
同樣)的爭論突破。 我的感覺是唯一好的MonadPlus
實例是Monoid
實例的副本,但其他實例不同。 盡管如此,圖書館在這個問題上仍然不一致,特別是在這個問題上(很多讀者都會看到我的這個古老的蟲子來了)......
... Maybe
的monoid實例,它忽略了我們經常使用Maybe
來模擬可能的失敗的事實,而是觀察到在一個額外的元素中使用相同的數據類型的想法可以用來給半群提供一個中性元素,如果它還沒有。 這兩種結構產生了同構類型,但它們在概念上並不相同。 ( 編輯更糟糕的是,這種想法是實現得很笨拙,給人實例Monoid
約束,當只有一個Semigroup
是必要的。我想看到的Semigroup
-extends-TO- Monoid
的想法實現的,而不是 Maybe
。)
特別是回到Kleisli
,我們有三個明顯的候選實例:
Monoid (Kleisli maa)
帶有return
和Kleisli組成 MonadPlus m => Monoid (Kleisli mab)
提升mzero
和mplus
逐點->
Monoid b => Monoid (Kleisli mab)
升降的幺半結構b
在m
然后->
我希望沒有做出任何選擇,只是因為不清楚做出哪個選擇。 我猶豫不決,但我的投票將是2,優先考慮來自Kleisli ma
的結構來自b
的結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.