为数据类型定义fmap

ito*_*nva 0 haskell functor

所以我有这些数据类型:

data Stuff a = Stuff (StuffPart a) (StuffPart a) deriving (Show,Eq)
data StuffPart a = Add a (StuffPart a)| End deriving (Show,Eq)
Run Code Online (Sandbox Code Playgroud)

,现在可以为Stuff写一个fmap函数吗?就像是 :

instance Functor Stuff
  where 
   fmap f (Stuff x y) = Stuff (f x) (f y)
Run Code Online (Sandbox Code Playgroud)

显然我的fmap不起作用,但我能做些什么来使它工作.我也试过像这样的代码:

instance Functor Stuff
  where 
   fmap f (Stuff x y) = Stuff (f x) (fmap f y)
Run Code Online (Sandbox Code Playgroud)

不知怎的,我觉得在fmap函数方面迷失了..

Wil*_*sem 6

fmap 有签名:

fmap :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

所以这意味着它将 - 给定一个映射ab的函数,生成一个映射Stuff a到的函数Stuff b.但是属性Stuff不是as,所以你不能f直接调用参数.

所以这可能意味着你想先做StuffPart a一个Functor.例如:

instance Functor StuffPart where
    fmap f (Add x y) = Add (f x) (fmap f y)
    fmap _ End = End
Run Code Online (Sandbox Code Playgroud)

它看起来像是StuffPart你的自定义列表([]).

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

instance Functor Stuff where
    fmap f (Stuff x y) = Stuff (fmap f x) (fmap f y)
Run Code Online (Sandbox Code Playgroud)

请注意,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
Run Code Online (Sandbox Code Playgroud)


Lee*_*Lee 5

您还需要一个Functor实例StuffPart:

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
Run Code Online (Sandbox Code Playgroud)