为数据类型定义 fmap



所以我有这些数据类型:

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

,现在是否可以为 Stuff 编写 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 函数方面感到迷茫..

fmap具有以下签名:

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

所以这意味着它将 - 给定一个从a映射到b的函数,产生一个将Stuff a映射到Stuff b的函数。但是Stuff的属性不是a的,因此您不能直接对参数调用f

所以这可能意味着你想先StuffPart a做成Functor。例如:

instance Functor StuffPart where
fmapf (Add x y) = Add (f x) (fmapf y)
fmap_ End = End

看起来StuffPart是列表的自定义定义([])。

然后我们可以简单地定义:

instance Functor Stuff where
fmap f (Stuff x y) = Stuff (fmapf x) (fmapf 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 (foox) (fooy)
wherefoo(Add x y) = Add (f x) (fooy)
fooEnd = End

您还需要一个用于StuffPartFunctor实例:

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

最新更新