Вы не можете;Either a
может быть функтором, потому что частичное применение Either
имеет вид * -> *
, но вы не можете сделать частичное применение справа.
Вместо этого вас может заинтересовать Bifunctor
экземпляр Either
:
instance Bifunctor Either where
bimap f _ (Left a) = Left (f a)
bimap _ g (Right b) = Right (g b)
bimap
принимает две функции, по одной для каждого из двух типов, заключенных в Either
.
> bimap (+1) length (Left 3)
Left 4
> bimap (+1) length (Right "hi")
Right 2
Также есть функции first
и second
, которые фокусируются на одном или другом типе.second
соответствует обычному fmap
для Either
;first
- это функция, которую вы ищете.
> first (+1) (Left 3)
Left 4
> first (+1) (Right 3)
Right 3
> second (+1) (Left 3)
Left 3
> second (+1) (Right 3)
Right 4
(отзыв на @leftaroundabout)
Модуль Control.Arrow
обеспечивает функцию left
, которая эффективнотакой же, как second
, но с более описательным именем и другим производным.Сравните их типы:
> :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
жестко запрограммирован для работы с функциями и может быть ограничен p ~ Either
.left
жестко запрограммирован для работы с Either
и может быть ограничен a ~ (->)
.
Смущает, что Control.Arrow
также обеспечивает функцию second
, котораяаналогичен экземпляру Bifunctor
для кортежей:
> :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