0
votes

So I've got those data types :

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

, now is it possible to write a fmap function for Stuff ? Something like :

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

Obviously my fmap won't work but what can I do to make it work. I have also tried code like :

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

Somehow I feel lost in terms of fmap functions..

2
you need one for StuffPart, same as a list... Or just enable DeriveFunctor to do the job for you...karakfa

2 Answers

6
votes

fmap has the signature:

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

So that means that it will - given a function that maps from a to b, produce a function that maps Stuff a to Stuff b. But the attributes of Stuff are not as, so you cannot call f on the arguments directly.

So that probably means you want to make StuffPart a a Functor first. For instance:

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

It looks like StuffPart is your custom defintion of a list ([]).

and then we can simply define:

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

Note that the fmaps we call here (the ones in boldface) refer to the function we defined above (in the context of Functor StuffPart).

EDIT: you do not have to make StuffPart a Functor per se. If you do not really want that, you can simply define a function foo :: (a -> b) -> StuffPart a -> StuffPart b and call that function, but this actually looks like bad code design to me, since if you later alter the definition of StuffPart then parts about Stuff have to change as well, making it harder. But if you really want that, you can use:

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
5
votes

You also need a Functor instance for 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