6
votes

I have been reading "Learn You A Haskell For Great Good!" and right now I am on "The Functor Typeclass" section.

Here they make Either into a functor by fixing the first type as follows:

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

So I wanted to ask, how could I make Either into a functor in the first type (by fixing the second type) instead, so that, I get the following definition for fmap

fmap f (Left x) = Left (f x)
fmap f (Right x)  = Right x
1
That's impossible unless you define it as data Either b a = Left a | Right b.Willem Van Onsem
Pay close attention to what they are doing; Either itself is not a functor, only the higher-kinded type resulting from the application of Either to an arbitrary type.chepner
This is a direct consequence of other design choices made in Haskell. See stackoverflow.com/a/44139690/383200 for some further discussion of those design choices and why they lead to this result.Carl
@chepner that is true, but can't we have some type level flip to do what @Willem Van Onsem said?Agnishom Chattopadhyay
@AgnishomChattopadhyay I had something similar in a different, deleted answer. It wasn't quite type-level, but defined a natural transformation eswap :: Either a b -> Either b a that could bracket the application of fmap f. (leftmap f = eswap . fmap f . eswap). Are you thinking of something analogous to newtype Compose f g a = Compose { getCompose :: f (g a) }, like newtype Flip f a b = Flip { getFlip :: f b a }?chepner

1 Answers

8
votes

You can't; Either a can be a functor because the partial application of Either has kind * -> *, but you can't do partial application from the right.

Instead, you might be interested in the Bifunctor instance of Either:

instance Bifunctor Either where
    bimap f _ (Left a) = Left (f a)
    bimap _ g (Right b) = Right (g b)

bimap takes two functions, one for each of the two types wrapped by Either.

> bimap (+1) length (Left 3)
Left 4
> bimap (+1) length (Right "hi")
Right 2

There are also first and second functions that focus on one or the other type. second corresponds to the regular fmap for Either; first is the function you are looking for.

> first (+1) (Left 3)
Left 4
> first (+1) (Right 3)
Right 3
> second (+1) (Left 3)
Left 3
> second (+1) (Right 3)
Right 4

(hat tip to @leftaroundabout)

The Control.Arrow module provides the left function, which effectively is the same as second, but with a more descriptive name and a different derivation. Compare their types:

> :t Data.Bifunctor.second
Data.Bifunctor.second :: Bifunctor p => (b -> c) -> p a b -> p a c
> :t Control.Arrow.left
Control.Arrow.left :: ArrowChoice a => a b c -> a (Either b d) (Either c d)

second is hard-coded to work with functions and can be restricted by p ~ Either. left is hard-coded to work with Either and can be restricted by a ~ (->).


Confusingly, Control.Arrow also provides a second function which is similar to the Bifunctor instance for tuples:

> :t Control.Arrow.second
Control.Arrow.second :: Arrow a => a b c -> a (d, b) (d, c)

> Control.Arrow.second (+1) (1,2) == Data.Bifunctor.second (+1) (1,2)
True