2017-06-18 98 views
1

定義FMAP所以我有這些數據類型:數據類型

data Stuff a = Stuff (StuffPart a) (StuffPart a) deriving (Show,Eq) 
data StuffPart a = Add a (StuffPart a)| End deriving (Show,Eq) 

,現在是有可能寫的東西一FMAP功能?喜歡的東西:

instance Functor Stuff 
    where 
    fmap f (Stuff x y) = Stuff (f x) (f y) 

顯然,我的FMAP不會工作,但我能做些什麼來使它發揮作用。 我也嘗試這樣的代碼:

instance Functor Stuff 
    where 
    fmap f (Stuff x y) = Stuff (f x) (fmap f y) 

不知怎的,我在FMAP功能方面感到失落..

+1

你需要一個'StuffPart',同一個列表...或者只是啓用'DeriveFunctor'爲你做這項工作... – karakfa

回答

6

fmap有簽名:

fmap :: Functor f => (a -> b) -> f a -> f b 

因此,這意味着它會 - 給一個映射從ab的函數會生成一個將Stuff a映射到Stuff b的函數。但是的屬性Stuff不是a s,所以你不能直接調用f的參數

因此,這可能意味着您首先想要使StuffPart a a Functor。例如:

instance Functor StuffPart where 
    fmap f (Add x y) = Add (f x) (fmap f y) 
    fmap _ End = End

它看起來像StuffPart是一個列表([])的自定義確定指標。

,然後我們可以簡單地定義:

instance Functor Stuff where 
    fmap f (Stuff x y) = Stuff (fmap f x) (fmap f y)

注意,fmap小號我們稱之爲這裏(粗體顯示的那些)是指我們上面(在Functor StuffPart的上下文中)中定義的功能。

編輯:你不使StuffPart一個Functor本身。如果你不是真的想要這樣,你可以簡單地定義一個函數foo :: (a -> b) -> StuffPart a -> StuffPart b並調用該函數,但這實際上對我來說看起來像不好的代碼設計,因爲如果稍後改變了StuffPart的定義,那麼關於Stuff的部分也必須改變,使它更難。但是,如果你真的想,你可以使用:

instance Functor Stuff where 
    fmap f (Stuff x y) = Stuff (foo x) (foo y) 
     where foo (Add x y) = Add (f x) (foo y) 
       foo End = End
+0

謝謝!哦,我明白了,但沒有其他選項可以做到這一點,而不必將Stuffpart變成Functor? – itonva

+1

@itonva:是的,你可以定義一個函數'foo ::(a - > b) - > StuffPart a - > StuffPart b',然後調用該函數。但是在這裏使'StuffPart'成爲一個函數似乎也是合理的。 –

+0

好吧,我明白了。感謝您的幫助,我真的很感謝:) – itonva

5

您還需要一個StuffPart例如Functor

instance Functor Stuff where 
    fmap f (Stuff p1 p2) = Stuff (fmap f p1) (fmap f p2) 

instance Functor StuffPart where 
    fmap f (Add x sp) = Add (f x) (fmap f sp) 
    fmap f End = End 
+0

@WillemVanOnsem - 更新,謝謝。 – Lee