Почему для Either нет альтернативного экземпляра, кроме полугруппы, которая ведет себя аналогично альтернативе?
Я новичок в Haskell, и мне интересно, почему нет альтернативного варианта Either
но полугруппа, которая ведет себя так, как я ожидал бы от альтернативы:
instance Semigroup (Either a b) where
Left _ <> b = b
a <> _ = a
Этот экземпляр отбрасывает или исправляет "ошибки", и когда оба операнда помечены как Right
Хватит первым. Разве это не тот "выбор", который предлагает альтернатива?
Я ожидаю, что экземпляр полугруппы будет выглядеть примерно так:
instance (Semigroup b) => Semigroup (Either a b) where
Left e <> _ = Left e
_ <> Left e = Left e
Right x <> Right y = Right (x <> y)
Это означает, что он распространяет ошибки и добавляет регулярные результаты.
Я полагаю, у меня неверное представление о Either
или из вовлеченных типов классов.
2 ответа
Что бы вы ожидали Alternative
экземпляр, чтобы дать вам. Я думаю, что это хороший способ почувствовать, как Alternative
а также Semigroup
отличается, чтобы посмотреть на другой тип, который имеет экземпляры для обоих: например, Maybe String
:
λ > Just "a" <> Just "b"
Just "ab"
λ > Just "a" <> Nothing
Just "a"
λ > Nothing <> Just "b"
Just "b"
λ > Nothing <> Nothing
Nothing
λ > Just "a" <|> Just "b"
Just "a"
λ > Just "a" <|> Nothing
Just "a"
λ > Nothing <|> Just "b"
Just "b"
λ > Nothing <|> Nothing
Nothing
Хорошо, так что основное отличие, похоже, заключается в Just "a"
а также Just "b"
, Это имеет смысл, поскольку вы объединяете их в случае Semigroup
вместо того, чтобы принять левый смещенный вариант в случае Alternative
,
Теперь, почему вы не могли иметь Alternative
экземпляр для Either
, Если вы посмотрите на функции, которые являются частью Alternative
тип класса:
λ > :i Alternative
class Applicative f => Alternative (f :: * -> *) where
empty :: f a
(<|>) :: f a -> f a -> f a
some :: f a -> f [a]
many :: f a -> f [a]
{-# MINIMAL empty, (<|>) #-}
Похоже, это определяет понятие empty
; это личность (<|>)
оператор. Идентичность в данном случае означает, что альтернативой между идентичностью и чем-то еще всегда является нечто иное.
Теперь, как бы вы создали личность для Either e a
? Если вы посмотрите на ограничение на Alternative
Например, вы можете видеть, что это требует f
иметь Applicative
пример. Все в порядке, Either
имеет Applicative
экземпляр объявлен для Either e
, Как вы можете видеть Either
является только аппликативным функтором для переменной второго типа (a
в случае Either e a
). Так тож для Either e
потребуется e
также иметь личность. Пока можно построить тип где e
имеет экземпляр Alternative
Вы не можете сделать пример для Alternative
за Either
с этим e
потому что нет такого ограничения в определении класса типа (что-то вроде: (Alternative e, Applicative (f e)) => Alternative (f e)
).
TL; DR: Мне жаль, если я потерял тебя из-за своего бессвязного, если коротко f
в случае Either
неправильный вид, Alternative
требует f :: * -> *
в то время как Either
имеет вид Either :: * -> * -> *
Так Maybe
может иметь экземпляр Alternative
потому что это имеет вид Maybe : * -> *
и имеет понятие идентичности (Nothing
) что требуется empty
, Посмотрите на все случаи Alternative
и обратите внимание на тип каждого экземпляра типа данных.
Вы можете найти тип данных в ghci с помощью :k
:
λ > :k Maybe
Maybe :: * -> *
λ > :k Either
Either :: * -> * -> *
За билет Дитриха Эппа, размещенный выше, проблема с Alternative
является empty
, Если у вас есть:
instance Alternative (Either a) where ...
Вы должны быть в состоянии извлечь некоторую ценность Either a b
"из воздуха", который был вашим объектом идентичности. Одним из возможных примеров может быть:
instance (Monoid a)=> Alternative (Either a) where
empty = Left mempty
...
Вы также спрашиваете, почему Semigroup
экземпляр определен так, как есть, и, честно говоря, я тоже не понимаю. Казалось бы, предлагаемый вами случай также разрешил бы (совместимый / законный) Monoid
например,
instance Monoid b=> Monoid (Either a b) where
mempty = Right mempty
И это будет соответствовать Maybe
экземпляр (алгебраические отношения между Maybe и Either очевидны).
Так что ситуация не очень хорошая. Часть вопроса Alternative
это своего рода класс второго класса, если хотите; это моноидальная вещь высшего рода, но ее отношение к Monoid
а также Semigroup
который явно и явно (в документах) образует иерархию, не определен.
Я уверен, что в списке рассылки библиотек было много дискуссий, и если есть какие-то очевидные "правильные" решения, вполне вероятно, что переход к ним может привести (в худшем случае к молчанию) поломку.