2013-11-04 64 views
21

Exercise 5 of the Haskell Typeclassopedia Section 3.2詢問的聲明組成兩個Functor是什麼意思?

證明或反2函子的組成也是一個函子。

我開始還以爲這是在談論組成由Functor兩個單獨的實例定義的fmap方法,但並沒有真正意義,因爲類型不匹配,據我可以告訴。對於ff'兩種類型,fmap的類型將是fmap :: (a -> b) -> f a -> f bfmap :: (a -> b) -> f' a -> f' b,並且這看起來並不是可組合的。那麼組成兩個Functors意味着什麼?

+2

你有沒有試過在ghci中自己編寫fmap?即':t fmap。 fmap' – Squidly

+0

@MrBones感謝您的提示!對於那些沒有ghci訪問權限的人來說,輸出是'::(Functor f1,Functor f)=>(a - > b) - > f(f1 a) - > f(f1 b)' – akbiggs

回答

24

Functor給出了兩個映射:一個在類型級別映射類型的類型(這是在instance Functor x wherex),和一個在水平術語映射函數以函數(這是在fmap = xx)。您正在考慮編寫術語級映射,但應考慮編寫類型級映射;例如,鑑於

data Compose f g x = Compose (f (g x)) 

你可以寫

instance (Functor f, Functor g) => Functor (Compose f g) 

?如果不是,爲什麼不呢?

+1

這是一個這個解釋Typeclassopedia練習的優秀答案並未提供解決方案。 – Will

11

兩個功能的組合物是當你把一個功能的另一功能的內部,如

round (sqrt 23) 

這是兩個函數roundsqrt組合物。同樣,二函子的組成是當你把一個仿另一個函子內,如

Just [3, 5, 6, 2] 

列表是一個仿函數,所以是有可能。如果你試圖找出fmap應該對上述值做什麼,你可以得到一些直覺,說明爲什麼它們的組成也是一個仿函數。當然,它應該映射內部仿函數的內容!

12

它確實有助於在這裏思考的範疇演繹,一個仿函數F: C -> D在一個類別D需要的對象(值)和態射(功能)的對象和態射從類別C對象和態射。

對於第二函子G : D -> E函子G . F : C -> E的組成只是把Ffmap變換的值域是Gfmap變換的域。在Haskell中,這是通過一些新的解開來完成的。

import Data.Functor 

newtype Comp f g a = Comp { unComp :: f (g a) } 

compose :: f (g a) -> Comp f g a 
compose = Comp 

decompose :: Comp f g a -> f (g a) 
decompose = unComp 

instance (Functor f, Functor g) => Functor (Comp f g) where 
    fmap f = compose . fmap (fmap f) . decompose 
+2

嘿!沒有破壞者! = P –

+1

'f'是否同時指'functor'和'function'?如果答案是肯定的,那麼爲什麼'Functor f'的類型約束不適用於'fmap f'中的'f'? – Kamel

12

這是怎麼講的是類型構造[]Maybe,不喜歡fmap的功能成分組成。因此,例如,有作曲[]Maybe的方法有兩種:

newtype ListOfMabye a = ListOfMaybe [Maybe a] 
newtype MaybeOfList a = MaybeOfList (Maybe [a]) 

聲明說,兩個Functors組成是Functor意味着有寫Functor實例爲這些類型的公式化方式:

instance Functor ListOfMaybe where 
    fmap f (ListOfMaybe x) = ListOfMaybe (fmap (fmap f) x) 

instance Functor MaybeOfList where 
    fmap f (MaybeOfList x) = MaybeOfList (fmap (fmap f) x) 

事實上,哈斯克爾平臺自帶的,讓你一個Compose類型,這是否「免費」的模塊Data.Functor.Compose

import Data.Functor.Compose 

newtype Compose f g a = Compose { getCompose :: f (g a) } 

instance (Functor f, Functor g) => Functor (Compose f g) where 
    fmap f (Compose x) = Compose (fmap (fmap f) x) 

ComposeGeneralizedNewtypeDeriving延伸是特別有用的:

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

newtype ListOfMaybe a = ListOfMaybe (Compose [] Maybe a) 
    -- Now we can derive Functor and Applicative instances based on those of Compose 
    deriving (Functor, Applicative) 

注意,兩個Applicative S中的組合物也是一種Applicative。因此,由於[]MaybeApplicatives,因此Compose [] MaybeListOfMaybe。編寫Applicative s是一種非常簡潔的技術,這些技術現在正在逐漸變得越來越普遍,作爲monad變壓器的替代方案,用於不需要monad的全部功能的情況。

+0

這裏肯定是所有答案中最有用的。讓我進一步問你:當你寫fmap f(Compose x)時,x的類型是什麼?我會說它是f a,但我仍然努力想象計算(fmap(fmap f)x)。想要更多地關注getCompose。 注:我知道字母「f」在這裏用於兩種不同的角色。 –