Объявление экземпляра с переменными типа
Написание чего-то вроде этого работает нормально:
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)
Теперь допустим, что я хочу инвертировать это, Left применяет f к значению:
instance Functor (Either a) where
fmap _ (Right x) = Right x
fmap f (Left x) = Left (f x)
Это не компилируется, я думаю, мне нужно что-то вроде Functor (Either _ b)
, Как мне это сделать?
1 ответ
Вы не можете и не должны. Если бы вы могли сделать это, было бы намного сложнее узнать, fmap (+1) (Left 1)
должно быть Left 1
или же Left 2
,
Bifunctor
Тем не менее, абстракция, которую вы ищете (что-то, что может быть отображено с обеих сторон) существует и называется Bifunctor
, Затем, в зависимости от того, хотите ли вы отобразить Left
с или Right
s, вы используете first
или же 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
С другой стороны, если вы хотите придерживаться fmap
только и не парьтесь first
а также second
, вы можете обернуть ваш тип данных в Flip
newtype, который имеет эффект поиска экземпляра functor переменной второго типа. Вы все еще полагаетесь на то, что Either
это Bifunctor
, но вы избегаете first
а также 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