Instance declaration with type variables

115 views Asked by At

Writing something like this works fine:

data Either a b = Left a | Right b

instance Functor (Either a) where
    fmap _ (Left x) = Left x
    fmap f (Right x) = Right (f x)

Now lets say I want to invert this, Left applies f to value:

instance Functor (Either a) where
    fmap _ (Right x) = Right x
    fmap f (Left x) = Left (f x)

This doesn't compile, I suppose I need to have something like Functor (Either _ b), how do I do this?

1

There are 1 answers

0
Alec On

You can't, and you shouldn't. If you could do this, it would make it a lot tougher to know whether fmap (+1) (Left 1) should be Left 1 or Left 2.

Bifunctor

That said, the abstraction you are looking for (something which can be mapped over on either side) exists and is called a Bifunctor. Then, depending on whether you want to map over the Lefts or the Rights, you use first or second:

ghci> first (+1) (Left 1)
Left 2
ghci> second (+1) (Left 1)
Left 1
ghci> first (+1) (Right 1)
Right 1
ghci> second (+1) (Right 1)
Right 2

Flip

Alternately, if you want to stick to fmap only and not be bothered with first and second, you can wrap your data type in the Flip newtype, which has the effect of looking for the functor instance of the second type variable. You still rely on the fact that Either is a Bifunctor, but you avoid first and second:

ghci> fmap (+1) (Flip (Left 1))
Flip (Left 2)
ghci> fmap (+1) (Left 1)
Left 1
ghci> fmap (+1) (Flip (Right 1))
Flip (Right 2)
ghci> fmap (+1) (Right 1)
Right 1