В чем идея библиотек Haskell, генерирующих исключения

Почему библиотека (например, wreq на 404) генерирует исключение вместо того, чтобы переносить результат во что-то вроде Maybe?

Наивно, я думаю, что Maybe был бы лучше (компилятор предупреждает меня, например, если я не обрабатываю все случаи). Почему я здесь не прав?

Кому-то понравится то же самое, кому-то понравятся их исключения. Боюсь, это очень самоуверенно.

typetetris 25.10.2018 14:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
1
317
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хаскеллеры очень стараются избегать генерации исключений из функции - функция должна генерировать исключение только в действительно исключительных случаях, то есть в ситуациях «этого никогда не должно происходить», например, когда пользователь передает какой-либо ввод, который явно запрещен документацией. Если бы чистые функции регулярно генерировали исключения, это было бы большой проблемой не только потому, что тип не говорит, что нужно быть готовым к перехвату, а также одно исключение перехвата не могу внутри чистой функции, но только в коде IO, который вызывает функцию. И даже если вы в принципе можете перехватить исключение, может быть трудно предсказать куда, что это нужно сделать, потому что ленивое вычисление может задержать момент, когда это действительно произойдет.

На самом деле, даже в случае, например, Wreq.get, из функции не генерируется исключение.

Prelude Network.Wreq> get "htt:/p/this-isn't even valid URL syntax" `seq` "Ok"
"Ok"

Это действие IO, который выдает, когда вы его выполняете:

Prelude Network.Wreq> get "htt:/p/this-isn't even valid URL syntax" >> pure ()
*** Exception: InvalidUrlException "htt:/p/this-isn't%20even%20valid%20URL%20syntax" "Invalid scheme"

Теперь с экшеном IO ситуация немного иная. Много действий IO может иметь потенциально очень разные ошибки в разных ситуациях, которые трудно или невозможно предсказать, например, сбой жесткого диска. Каталогизация всех возможных ошибок в подходящем типе данных для каждого действия была бы серьезной задачей, и было бы действительно довольно громоздко обрабатывать все возможные случаи или выяснять, какие части просто передать. А простая упаковка результата каждого отдельного действия IO в Maybe приведет к аналогичной ситуации, как в Java, где каждая ссылка может иметь значение null. Это вам ни о чем не говорит, и люди часто не могут придумать разумных способов справиться с этим.

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

Это не значит, что для действия IO никогда не имеет смысла возвращать значение Maybe / Either, которое делает возможные ошибки явными, просто это не всегда имеет смысл.

Наверное, следует добавить, что вы можете легко проигнорировать возвращаемое значение Left, если действие IO вернуло Either вместо выброса. Но если вы проигнорируете сгенерированное исключение, ваша программа выйдет из строя. Хорошо, конечно, вы также можете игнорировать исключение, но вам нужно больше работать над этим, можно возразить. Но, как я сказал ранее, это, вероятно, тоже будет очень самоуверенным.

typetetris 25.10.2018 15:13

FWIW, моя любимая теория состоит в том, что причина, по которой исключения были изобретены / популярны в процедурных языках, заключается в том, что традиционные процедурные языки делают представление, создание и использование типов суммы настолько болезненным; Мне часто хотелось, чтобы конструкция на C была такой же синтаксически дешевой, как Either, например

Daniel Wagner 25.10.2018 15:14

@Krom, если вы проигнорируете возвращаемое значение Left, вы тем самым превратите (надеюсь) описательное сообщение об ошибке в непостижимое исключение исчерпывающих шаблонов. И вылететь из программы с помощью что. Если вы проигнорируете исключение, созданное самим действием, оно выйдет из строя с (опять же, с надеждой) описательным сообщением об исключении.

leftaroundabout 25.10.2018 15:19

В некоторых случаях (например, с пакетом http) я думаю, что действительно имеет смысл различать условия, которые вызывающий почти наверняка хочет обрабатывать локально (тайм-аут сети, страница не найдена и т. д.), И те, которые с большей вероятностью перейдут в обработчик более высокого уровня (исключения, созданные другим потоком, несуществующий сетевой интерфейс и т. д.).

dfeuer 25.10.2018 18:27

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

leftaroundabout 25.10.2018 18:32

@leftaroundabout, это определенно суждение. Но для исключений много единственная разумная вещь, которую можно сделать в приложениях самый, - позволить ему пройти весь путь вверх и убить поток. Пользователи всегда несут ответственность за то, чтобы их программы регистрировали / уведомляли надлежащим образом, когда что-то неожиданно умирает.

dfeuer 25.10.2018 18:43

Другие вопросы по теме