2011-12-02 46 views

回答

50

這裏是一個完全參數化的例子:

data Weird a = Weird a (a -> a) 

instance Foldable Weird where 
    foldMap f (Weird a b) = f $ b a 

Weird不是Functor因爲發生在負位置a

+0

哦,真好!甚至沒有想到這一點。不知道標準庫中是否有'Foldable'實例由於逆變而不能成爲'Functor'? –

+0

我認爲你可以用特定的擴展名和類型同義詞做到這一點。 – PyRulez

41

下面是一個簡單的例子:Data.Set.SetSee for yourself.

如果檢查類型爲Set定義的專門foldmap功能的原因應該是顯而易見的:

foldr :: (a -> b -> b) -> b -> Set a -> b 

map :: (Ord a, Ord b) => (a -> b) -> Set a -> Set b 

由於數據結構依賴於二叉搜索樹內部,一個Ord約束元素需要。 Functor實例必須允許任何元素類型,所以這是不可行的,唉。

另一方面,摺疊始終會破壞樹以生成彙總值,因此無需對摺疊的中間結果進行排序。即使摺疊實際上構建了新的Set,滿足Ord約束的責任在於傳遞給摺疊的積累函數,而不是摺疊本身。

同樣可能適用於任何不完全參數化的容器類型。考慮到Data.Set的效用,這讓你引用的關於「有趣的」Foldable的評論似乎有點可疑,我想!

+8

這確實是'Foldable'的一個例子,它不能成爲'Functor'。然而,這似乎更多的是由於Haskell的類型系統無法表達「Set」僅適用於Ord類型,並且使某個Functor只需要爲類型定義'fmap'有道理,正如其他地方所定義的那樣「,而不是由於」Set「和」Functor「所代表的固有內容。無論如何,謝謝你的例子。 :-) – Prateek

+5

@Prateek:是的,沒有。完全參數化是「Functor」所代表的內在特性。也就是說,比標準的Haskell(包括實際上由GHC支持的全類型系統)更具表現力的類型系統可以表達「對某類類型的完全參數化」,這就是這裏所期望的。 –

+5

@Prateek:從更數學的意義上說,「Functor」只包含特定種類的函子,從所有Haskell類型到它自己的適當子類別。它不能表達只能在子類別上操作的函子,或者其他可能有意義的東西。儘管如此,Sjoerd Visscher的例子仍然比我的更有趣和更深奧。 :] –

21

閱讀Beautiful folding 我意識到,任何Foldable可以通過包裝它製成一個Functor

data Store f a b = Store (f a) (a -> b) 

用一個簡單的智能構造器:

store :: f a -> Store f a a 
store x = Store x id 

(這只是一個Store的變種comonad數據類型。)

現在我們可以定義

instance Functor (Store f a) where 
    fmap f (Store x g) = Store x (f . g) 

instance (F.Foldable f) => F.Foldable (Store f a) where 
    foldr f z (Store x g) = F.foldr (f . g) z x 

這樣一來,我們就可以使雙方Data.Set.Set和Sjoerd Visscher的的Weird函子。 (但是,如果我們在fmap中使用的函數是複雜的,因爲結構不會記憶它的值,所以反覆摺疊它可能是非常低效的。)


更新:這還提供了其爲算符,可摺疊的但不是遍歷的一個結構的例子。要使Store可以穿越,我們需要使(->) r可以穿越。所以我們就需要實現

sequenceA :: Applicative f => (r -> (f a)) -> f (r -> a) 

讓我們Either bf。然後,我們就需要實現

sequenceA' :: (r -> Either b a) -> Either b (r -> a) 

顯然,有沒有這樣的功能(你可以用Djinn驗證)。所以我們既不能實現sequenceA

+0

Store數據類型完全是任何類型構造函數的自由函子,也稱爲Coyoneda(https://hackage.haskell.org/package/kan-extensions-4.2.3/docs/Data-Functor-Coyoneda.html) 。 –

+0

@KrisNuttycombe不完全。 Coyoneda在'Store'不存在的地方是存在量化的。 – Carl