"a" <> Just "b"
Just "ab"
λ> Right "a" <> Right "b"
Right "a"
То есть почему Either не конкатенируется (как Maybe, например)?
Я интуитивно ожидал, что оно должно как-то так работать:
(<>) er@(Left _) _ = er
(<>) _ er@(Left _) = er
(<>) (Right r1) (Right r2) = Right (r1 <> r2)
И второй тогда вопрос: есть какой-то стандартный класс, который бы работал для Either так, как я ожидал от Semigroup?
λ> Ap (Right "str") <> Ap (Right "str") Ap {getAp = Right "strstr"} λ> Ap (Right "str") <> Ap (Right "str") <> Ap (Left 12) <> Ap (Right "str") Ap {getAp = Left 12}
instance Semigroup (Either a b) С учётом, что здесь нет ограничений на a и b, нам в x <> y остаётся только что выбирать, что выйдет: x или y. У нас 4 случая (в зависимости от строения x и y). Выбираем что-либо для каждого и проверяем, соблюдаются ли законы полугруппы. Здесь решили так: x<>y |Left Right -----+---------- Left | y y Right| x x Но, предположим, как Вы и хотели, сделано instance Semigroup b => Semigroup (Either a b). Right x <> Right y = Right (x <> y), хорошо. А что делать, если Left x <> Right y? Мы всё равно пришли к тому, что надо просто выбирать что-то одно, не изменяя, в 3 случаях из 4, а 4-й просто дополнительно усложнён. Стоит ли это переусложнение того, чтобы быть имплементированным? Ну, видимо, люди решили, что не стоит.
А это переусложнение чем-то оличается от того, что реализовано в Maybe?
Да: там Nothing идёт без типа. Т.е. там мы к типу только одно значение добавляем, а тут мы два типа складываем. Кстати, как правильно заметил @sand_witch, то "усложнение" всё равно реализовали, но не как основное, а как дополнительное (через Ap).
так исторически сложилось. законам не противоречит. а друг с другом они не должны быть связаны по поведению, так что всем ок
для Maybe решили усложнить, чтобы на сдачу получился простой способ превращения произвольной полугруппы в моноид. простое поведение вынесли в отдельный типы First и Last
Вы можете свой класс сделать по типу семигруп и свой инстанс для Either
Обсуждают сегодня