你失去的最大的東西是多態遞歸。考慮Okasaki的catenable名單:
data Cat q a = Empty | Cat a (q (Cat q a))
我們可以寫
instance Foldable q => Foldable (Cat q) where
foldMap _ Empty = mempty
foldMap f (Cat a q) = f a <> foldMap (foldMap f) q
但是,如果我們嘗試使用剛剛MonoFoldable
,我們就完蛋了。在q
,forall x . (MonoFoldable (q x), Element (q x) ~ x)
上的必要實例約束不能以任何常規方式表達。這可能與Data.Constraint.Forall
有關,但它變得非常難看。
一個較小的問題是代碼可能會得到更復雜的類型簽名。例如,
osum :: (MonoFoldable c, Num (Element c)) => c -> Element c
令我不如
sum :: (Foldable f, Num n) => f n -> n
修復的方法是簡單的:改變MonoFoldable
的定義
class (a ~ Element c) => MonoFoldable' a c where ...
這將使你
osum' :: (MonoFoldable' n c, Num n) => c -> n
可替代地,廢Element
乾脆,並使用
class MonoFoldable'' a c | c -> a
其給出類似的簡化簽名。
不幸的是,Michael Snoyman在這一點上與我不同意。我可能會寫一些自己的包裝程序包來公開我的首選API。
它需要'TypeFamilies'而'摺疊'不適合一個? – Cubic
不是直接的答案,而是'MonoFoldable'的堂兄['MonoFunctor'](https://hackage.haskell.org/package/mono-traversable-1.0.0.1/docs/Data-MonoTraversable.html#t:MonoFunctor )不如'Functor',因爲你不能改變它裏面的東西的類型。 'MonoTraversable'也一樣# –
我相信'MonoFoldable'全面概括了'Foldable',注意你提到的錯誤消息和類型擴展。正如@BenjaminHodgson所提到的那樣,層次結構中的其他類不能滿足這個要求。如果有人對此有反例,我會感興趣,因爲我沒有證據表明這種信念是正確的。 –