Какой цели служит сложность «кроме» в Haskell? - PullRequest
0 голосов
/ 24 ноября 2018

Я понимаю (я думаю), что в Haskell существует тесная связь между Either и Except, и что ее легко преобразовать из одного в другое.Но меня немного смущают лучшие практики обработки ошибок в Haskell и то, при каких обстоятельствах и сценариях я бы выбрал одно из другого.Например, в примере , представленном в Control.Monad.Except, Either используется в определении

type LengthMonad = Either LengthError

, так что calculateLength "abc" равно

Right 3

Если бы вместо этого нужно было определить

type LengthMonad = Except LengthError

, тогда calculateLength "abc" было бы

ExceptT (Identity (Right 3))

Я запутался в том, для какой цели это будет служить и когда кто-то захочет этого.Почему все, что возвращается из calculateLength, всегда имеет Identity;почему бы не просто SomeExceptionType (Right 3) или даже SomeSuccessType 3?

Я новичок в Haskell, когда дело доходит до таких понятий, поэтому конкретный пример, когда я бы хотел, чтобы второе было над первым, было бы намногоценится, особенно почему это так (по-моему, мне) сложно.Например, что может сделать вызывающая функция, которая использует Except версию calculateLength, которую они не могут (или, по крайней мере, не так легко) сделать с Either версией?

1 Ответ

0 голосов
/ 24 ноября 2018

Аннотация

Используйте Either для нормальных успех / ошибка API.Он определен в библиотеке base , поэтому он не распространяет другие зависимости на потребителя.Кроме того, это один из самых базовых типов Haskell, поэтому «все» понимают, как он работает.

Используйте ExceptT только в том случае, если вам нужно специально объединить Either с другой монадой (например, например,IO).Этот тип определен в библиотеке transformers , поэтому он требует дополнительной зависимости от потребителей.Кроме того, монадные преобразователи - это более продвинутая функция Haskell, поэтому нельзя ожидать, что все поймут, как ее использовать.

Предположение о причинах

Меня не было рядом, когда принимались эти решениясделал, но кажется, что существуют разные исторические причины для путаницы .Haskell - это старый язык (более старый, чем Java!), Поэтому, хотя были предприняты попытки упростить его и исправить старые ошибки, некоторые все еще остаются.Насколько я могу судить, путаница Either / ExceptT является одной из таких ситуаций.

Я предполагаю , что Either старше концепции монадных трансформаторовпоэтому я представляю, что тип Either был введен в библиотеку base в начале истории Haskell.

То же самое можно сказать и о Maybe.

Другие монады, например, Reader и State , кажется, были введены (или, по крайней мере, "повторно") вместе с их монадными трансформаторами.Например, Reader это просто особый случай из ReaderT, где «другое» Monad равно Identity:

type Reader r = ReaderT r Identity

То же самое относится к StateT:

type State s = StateT s Identity

Это общая схема для многих монад, определенных в библиотеке transformers .ExceptT просто следует шаблону, определяя Except как особый случай ExceptT.

Есть исключения из этого шаблона.Например, MaybeT не определяет Maybe как особый случай.Опять же, я считаю, что это по историческим причинам;Maybe, вероятно, существовал задолго до того, как кто-то начал работать над библиотекой transformers .

История с Either кажется еще более запутанной.Насколько я могу судить, там был , первоначально, EitherT монадный трансформатор, но, очевидно, (я забыл детали) было что-то не так с его поведением (возможно, оно нарушало некоторые законы)Таким образом, он был заменен другим трансформатором с именем ErrorT, который снова оказался неправильным.В третий раз, я полагаю, это очарование, поэтому было введено ExceptT.

Модуль Control.Monad.Trans.Except следует шаблону большинства других монадных преобразователей, определяя «неэффективный» особый случай с использованием псевдонима типа:

type Except e = ExceptT e Identity

Я полагаю, что это так, потому что это возможно, но это может быть неудачно, потому что это сбивает с толку.Существует определенный уровень техники, который предполагает, что монадный преобразователь не должен следовать этому шаблону (например, MaybeT), поэтому я думаю, что было бы лучше, если бы модуль не сделал этого, но это происходит, и именно здесьявляются.

Я бы по существу проигнорировал тип Except и использовал бы вместо него Either, но использовал бы ExceptT, если требуется трансформатор.

...