Объявление экземпляра с переменными типа

Написание чего-то вроде этого работает нормально:

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
Другие вопросы по тегам