A Foldable
實例很可能是某種容器,因此也可能是Functor
。事實上,this說Haskell:一個不是Functor(或者不可穿越)的Foldable的例子?
一個
Foldable
類型也是一個容器(雖然類不技術上需要Functor
,有趣Foldable
s爲所有Functor
S)。
那麼,有一個Foldable
的一個例子,其是不天然一個Functor
或Traversable
? (這可能是Haskell的wiki頁面錯過了:-))
A Foldable
實例很可能是某種容器,因此也可能是Functor
。事實上,this說Haskell:一個不是Functor(或者不可穿越)的Foldable的例子?
一個
Foldable
類型也是一個容器(雖然類不技術上需要Functor
,有趣Foldable
s爲所有Functor
S)。
那麼,有一個Foldable
的一個例子,其是不天然一個Functor
或Traversable
? (這可能是Haskell的wiki頁面錯過了:-))
這裏是一個完全參數化的例子:
data Weird a = Weird a (a -> a)
instance Foldable Weird where
foldMap f (Weird a b) = f $ b a
Weird
不是Functor
因爲發生在負位置a
。
下面是一個簡單的例子:Data.Set.Set
。 See for yourself.
如果檢查類型爲Set
定義的專門fold
和map
功能的原因應該是顯而易見的:
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
的評論似乎有點可疑,我想!
這確實是'Foldable'的一個例子,它不能成爲'Functor'。然而,這似乎更多的是由於Haskell的類型系統無法表達「Set」僅適用於Ord類型,並且使某個Functor只需要爲類型定義'fmap'有道理,正如其他地方所定義的那樣「,而不是由於」Set「和」Functor「所代表的固有內容。無論如何,謝謝你的例子。 :-) – Prateek
@Prateek:是的,沒有。完全參數化是「Functor」所代表的內在特性。也就是說,比標準的Haskell(包括實際上由GHC支持的全類型系統)更具表現力的類型系統可以表達「對某類類型的完全參數化」,這就是這裏所期望的。 –
@Prateek:從更數學的意義上說,「Functor」只包含特定種類的函子,從所有Haskell類型到它自己的適當子類別。它不能表達只能在子類別上操作的函子,或者其他可能有意義的東西。儘管如此,Sjoerd Visscher的例子仍然比我的更有趣和更深奧。 :] –
閱讀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 b
爲f
。然後,我們就需要實現
sequenceA' :: (r -> Either b a) -> Either b (r -> a)
顯然,有沒有這樣的功能(你可以用Djinn驗證)。所以我們既不能實現sequenceA
。
Store數據類型完全是任何類型構造函數的自由函子,也稱爲Coyoneda(https://hackage.haskell.org/package/kan-extensions-4.2.3/docs/Data-Functor-Coyoneda.html) 。 –
@KrisNuttycombe不完全。 Coyoneda在'Store'不存在的地方是存在量化的。 – Carl
哦,真好!甚至沒有想到這一點。不知道標準庫中是否有'Foldable'實例由於逆變而不能成爲'Functor'? –
我認爲你可以用特定的擴展名和類型同義詞做到這一點。 – PyRulez