Search code examples
haskellfunctor

Defining fmap for data type


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..


Solution

  • 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