2016-09-22 46 views
5

MonoFoldablemono-traversable包似乎能夠實現所有通常的摺疊容器和更多,例如,像Bytestring和同質元組可以製作MonoFoldable而不是Foldable。我的問題是,除了需要一些先進的GHC功能之外,我們是否從MonoFoldable中失去了我們在Foldable中沒有的任何東西,這使得它對實例編寫者來說稍微更棘手,並且可能會得到更醜陋的錯誤消息?MonoFoldable會帶來什麼損失嗎?

例如,是否有一些代碼,當使用Foldable編譯但MonoFoldable類型不是推斷,例如?或者其他任何使得客戶端(不是實例編寫器代碼)更簡單的FoldableMonoFoldable

+0

它需要'TypeFamilies'而'摺疊'不適合一個? – Cubic

+4

不是直接的答案,而是'MonoFoldable'的堂兄['MonoFunctor'](https://hackage.haskell.org/package/mono-traversable-1.0.0.1/docs/Data-MonoTraversable.html#t:MonoFunctor )不如'Functor',因爲你不能改變它裏面的東西的類型。 'MonoTraversable'也一樣# –

+5

我相信'MonoFoldable'全面概括了'Foldable',注意你提到的錯誤消息和類型擴展。正如@BenjaminHodgson所提到的那樣,層次結構中的其他類不能滿足這個要求。如果有人對此有反例,我會感興趣,因爲我沒有證據表明這種信念是正確的。 –

回答

2

您失去參數。

類型(Foldable f) => f a -> [a]提供與(MonoFoldable c) => c -> [Element c]明顯不同的擔保。

你可以玩一個自由定理生成器來獲得屬性的一些想法,但作爲一個簡單的例子,前一種類型提供了輸出中出現輸出中的任何元素必須的屬性。這種性質不能由後一種類型保證。

2

你失去的最大的東西是多態遞歸。考慮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。

相關問題