Исключения в Хаскеле - PullRequest
6 голосов
/ 06 января 2012

Если я правильно понял, исключения в Haskell в основном предназначены для работы в монаде IO.По крайней мере, исключение может быть поймано внутри монады ввода / вывода.

Но иногда даже чистые функции могут выдавать исключение, например read "..." :: Int (когда чтение строки не представляет целое число), оператор (!!) (когда мы пытаемся получитьпункт вне списка), и так далее.И это истинное поведение, я не отрицаю.Однако я не хотел бы менять сигнатуру функции просто для того, чтобы она могла перехватить возможное исключение, потому что в этом случае мне нужно изменить сигнатуру всех функций по стеку вызовов раньше.

Есть ли какой-то шаблон для решенияза исключением более удобных в Haskell, из монады ввода-вывода?Может быть, я должен использовать unsafePerformIO в этом случае?Насколько «безопасно» использовать unsafePerformIO только для отлова исключений в чистых функциях?

Ответы [ 4 ]

10 голосов
/ 06 января 2012

В чистом коде обычно лучше всего избегать исключений. То есть не используйте head, если вы не уверены, что список не пустой, и используйте reads и сопоставление с шаблоном вместо read для проверки ошибок синтаксического анализа.

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

Обратите внимание, что здесь я говорю только о чистом коде, исключения в IO имеют свое применение при работе с исключительными случаями, которые иногда случаются при взаимодействии с "реальным миром". Однако с чистыми механизмами, такими как Maybe и ErrorT, работать проще, поэтому их часто предпочитают.

5 голосов
/ 06 января 2012

Вот для чего нужны монады! (Ну, не только это, но обработка исключений - одно из применений монадических идиом)

Вы делаете измените сигнатуру функций, которые могут выйти из строя (потому что они меняют семантику, и вы хотите отразить как можно большую часть семантики в типе, как правило). Но код, который использует эти функции, не обязательно должен соответствовать шаблону каждой отказавшей функции; они могут связываться, если им все равно:

head :: [a] -> Maybe a

eqHead :: (Eq a) => [a] -> Maybe [a]
eqHead xs = do
    h <- head xs
    return $ filter (== h) xs

Таким образом, eqHead не может быть написано "чисто" (синтаксический выбор, альтернативы которого я хотел бы изучить), но он также не должен знать о Maybe -ности head, это нужно только знать, что head может потерпеть неудачу некоторым способом.

Это не идеально, но идея в том, что функции в Haskell не имеют такой же стиль, как Java. В типичном дизайне Haskell исключение обычно не происходит глубоко в цепочке вызовов. Вместо этого, глубокая цепочка вызовов полностью чиста, когда мы знаем, что все аргументы полностью определены и хорошо себя ведут, и проверка происходит на самых внешних уровнях. Таким образом, исключение, поднимающееся из глубины, на самом деле не является чем-то, что должно поддерживаться на практике.

Вопрос о том, является ли сложность выполнения причиной шаблонов проектирования или шаблонов проектирования причиной отсутствия функций, поддерживающих это, является предметом обсуждения.

3 голосов
/ 06 января 2012

Если вы ожидаете, что такая функция, как read, может вызвать исключение, то почему бы просто не реструктурировать свой код, чтобы избежать возможности возникновения исключения?

В качестве более прямого ответа на ваш вопрос есть ложка .

2 голосов
/ 06 января 2012

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

Одной из основных сильных сторон чистых функций (и FP) является способность рассуждать о вашем коде в духе «если функция имеет тип [a] -> a, то для all списки типа a, я верну значение типа a. "Исключения как это вырезать ноги из-под этого.

Хорошая причина для того, чтобы head был таким, какой он есть, в том, что для новичков намного проще выучить манипуляции со списком до Maybe и друзей.Но если вы сможете понять лучший способ сделать это, я бы избежал этих рисков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...