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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With