Зачем нам нужно быть Монадой над Либо Монадой

Я играл вокруг Maybe и Либо типов монады (Chaining, применяя условные функции в соответствии с возвращенным значением, также возвращал сообщение об ошибке, вызванное функцией цепочки и т.д.). Поэтому мне кажется, что мы можем добиться того же и большего количества вещей, которые, возможно, делают, используя любую монаду. Итак, мой вопрос заключается в том, где практическая или концептуальная разница между ними?

Ответ 1

Вы, конечно, правы, что Maybe a изоморфен Either Unit a. Дело в том, что они часто семантически используются для обозначения разных вещей, что немного напоминает разницу между возвращением null и бросанием NoSuchElementException:

  • Nothing/None обозначает "ожидаемое" отсутствие чего-либо, а
  • Left e означает ошибку при получении по любой причине.

Тем не менее, мы могли бы даже совместить эти два с чем-то вроде:

query :: Either DBError (Maybe String)

где мы выражаем как возможность отсутствующего значения (DB null), так и ошибку в соединении, СУБД и т.д. (не говоря о том, что нет улучшенных конструкций, но вы получаете точку).

Иногда граница является жидкой; для saveHead :: [a] -> Maybe a можно сказать, что ожидаемая вероятность ошибки кодируется в намерении функции, а что-то вроде saveDivide может быть закодировано как Float -> Float -> Either FPError Float или Float -> Float -> Maybe Float, в зависимости от варианта использования (опять же, просто некоторые глупые примеры...).

Если у вас есть сомнения, лучшим вариантом является, вероятно, использование пользовательского результата ADT с семантическим кодированием (например, data QueryResult = Success String | Null | Failure DBError) и предпочесть Maybe на простые случаи, когда он "традиционно ожидается" (субъективная точка, которая однако будет в основном ОК, если вы приобретете опыт).

Ответ 2

@phg ответ велик. Я буду возиться с чем-то, что помогло мне разобраться в этом, когда я их изучил:

  • Maybe - одно (значение) или none - то есть у вас есть значение или у вас ничего нет
  • Either - логическая дизъюнкция, но у вас всегда есть хотя бы одно (значение), то есть у вас есть один или другой, но не оба.

Maybe отлично подходит для таких вещей, как то, где вы можете иметь или не иметь значения - например, поиск элемента в списке. если список содержит его, мы получаем (Maybe x), иначе получим Nothing

Either - идеальное представление ветки в вашем коде - это будет идти так или иначе; Left или Right. Мы используем мнемонику, чтобы ее запомнить: Right - правильный (правильный) способ; Left - неправильный путь (ошибка). Это не только использование, но, безусловно, наиболее распространенное.

Я знаю, что вначале различия могут казаться утонченными, но на самом деле они подходят для самых разных вещей.

Ответ 3

Ну, вы видите, мы можем сказать это предельно, говоря, что все типы продуктов могут быть представлены только 2-мя корнями и всеми нерекурсивными типами сумм на Either. Чтобы дополнительно представить рекурсивные типы, нам нужен тип фиксированной точки.

Например, почему есть 4-кортежи (a,b,c,d), когда мы могли бы написать (a, (b, (c,d))) или (((a,b), c), d)?

Или почему есть списки, когда работает следующее?

data Y f = Y (f (Y f))

type List a = Y ((,) (Either () a))


nil = Y (Left (), undefined)

cons a as = Y (Right a, as)

infixr 4 cons

numbers = 1 `cons` 2 `cons` 3 `cons` nil

-- this is like foldl

reduce f z (Y (Left (), _)) = z
reduce f z (Y (Right x, xs)) = reduce f (f z x) xs


total = reduce (+) 0 numbers