2017-06-18 66 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