我一直想知道一個完整的、包羅萬象的背景關系instance Functor (f :.: g)會是什么。我腦海中立刻閃現的想法是:
newtype (f :.: g) a = Comp (f (g a))
instance (Functor f, Functor g) => Functor (f :.: g) where
fmap f (Comp x) = Comp (fmap (fmap f) x)
但是,兩個逆變函子也將組成協變,如下所示:
instance (Contravariant f, Contravariant g) => Functor (f :.: g) where
fmap f (Comp x) = Comp (contramap (contramap f) x)
已經不是一個有希望的開始。但是,我在技術上也注意到了這一點,f甚至g不必有 kind * -> *- 唯一的要求f :.: g :: * -> *是 thatf :: k -> *和g :: * -> kfor some k。這意味著非函子型別可以組成函子,例如
newtype Fix f = Fix (f (Fix f))
instance Functor (Fix :.: (,)) where
fmap f (Comp x) = Comp (go x) where
go (Fix (x,xs)) = Fix (f x,go xs)
Fix :.: (,)與型別同構Stream:
data Stream a = a :> Stream a
所以這似乎是一個不平凡的問題。這讓我開始思考——如果 Haskell 的Functortypeclass 表示從 Hask 到 Hask 的分類函子,這是否意味著型別像Fix并且(,)可能是其他類別的函子?這些類別是什么?
uj5u.com熱心網友回復:
是的,我們可以從建構式的形狀中準確讀出它的含義。我們先來看看(,)。
函(,)子
(,) :: * -> * -> *
這需要兩種型別并產生一種型別。直到同構,這等價于
(,) :: (*, *) -> *
即,我們不妨取消對函式的柯里化并同時接受兩個引數。所以(,)可以看成是Hask × Haskto的函子Hask,其中Hask × Hask是
Haskell 并沒有真正用于自然轉換的內置型別。使用Rank-N 型別,我們可以寫出正確的形狀
(forall a. f a -> g a)
這是自然變換的形狀,當然我們還沒有驗證相干性。所以我們只需要相信它滿足這個屬性。
考慮到所有這些抽象的廢話,如果Fix要成為 from Hask ^ Haskto的函子Hask,它應該自然轉換為普通的 Haskell 函式,并且它應該具有以下形狀。
fixmap :: (Functor f, Functor g) => (forall a. f a -> g a) -> Fix f -> Fix g
一旦我們有了這種型別,我們就可以相當容易地撰寫實作。
fixmap h (Fix inner) = Fix (h . fmap (fixmap h) $ inner)
或者,等效地(根據自然變換的規則),
fixmap h (Fix inner) = Fix (fmap (fixmap h) . h $ inner)
我不知道這種函子形狀的慣用名稱,也不知道包含它的型別類,但當然沒有什么能阻止你自己制作它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/517150.html
標籤:哈斯克尔作品函子范畴论
