Подтвердить что ты не робот

Значение исключений Haskell

В чем смысл исключений в Haskell? Единственное, что я вижу, это включить undefined или error в мой код, чтобы остановить запуск программ. В противном случае я рассматриваю программирование с исключениями как логический дефект дизайна. Но у Haskell есть расширенный модуль исключения Control.Exception, который используется Prelude. Я читал, что причина исключений в С++ заключалась в том, чтобы предотвратить много "функции вызова, а затем проверить статус" в коде. Но такие вещи можно отвлечь в Хаскелле. Единственная причина, по которой я могу наблюдать за обработкой исключений в Haskell, - это FFI для обработки чужих исключений, но только для внутреннего использования в функции Haskell, обертывающей вызов.

4b9b3361

Ответ 1

Кажется, что этот вопрос на самом деле обсуждался здесь: http://haskell.org/haskellwiki/Exception Я не знаю, был ли этот вопрос на самом деле ответственным, как указано.

Ответ 2

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

-- The reciprocal is not defined for the value 0
myRecip :: Fractional a => a -> a
myRecip x | x == 0    = throw DivideByZero
          | otherwise = 1 / x

Конечно, вы всегда можете обеспечить эту функцию "безопасным" способом:

safeRecip :: Fractional a => a -> Maybe a
safeRecip x | x == 0    = Nothing
            | otherwise = Just $ 1 / x

Возможно, нам нужно даже отвлечь этот шаблон

restrictInput :: (a -> Bool) -> (a -> b) -> (a -> Maybe b)
restrictInput pred f x = if pred x then Just (f x) else Nothing

safeRecip' = restrictInput (/= 0) myRecip

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

prop_recip x = x == (recip . recip) x

Потому что теперь результат recip x находится в Maybe. Есть полезные функции, которые вы можете делать с (a -> a) функциями, которые вы больше не можете делать. Теперь вам нужно подумать о том, как сочинять майбы. Это, конечно, тривиально, если вам удобны монады:

prop_recip 0 = (safeRecip >=> safeRecip) 0 == Nothing
prop_recip x = (safeRecip >=> safeRecip) x == Just x

Но в этом и заключается руб. Новички обычно знают почти ничего, когда речь заходит о монадической композиции. Комитет Haskell, так как многие из каналов #haskell irc быстро скажут вам *, сделали несколько довольно неуловимых решений относительно дизайна языка, чтобы удовлетворить новичков. Мы хотим сказать: "Вам не нужно знать монады, чтобы начать делать полезные вещи в Haskell". И я вообще согласен с этим чувством.

TL;DR Несколько быстрых ответов на вопрос: что такое исключение?

  • грязный взлом, поэтому нам не нужно полностью защищать наши функции.
  • механизм управления потоком "try/catch" для IO-монады (IO - это бит-бит, так почему бы вам не бросить try/catch в список грехов?)

Могут быть и другие объяснения.

См. также Отчет Haskell > Основной ввод/вывод > Обработка исключений в IO Monad

* Я действительно спросил у #haskell irc, если они одобрили это утверждение. Единственный ответ, который я получил, был "wonky" :), поэтому, очевидно, это оправдано отсутствием возражений.


[Изменить] Обратите внимание, что error и undefined определены в терминах throw:

error :: [Char] -> a
error s = throw (ErrorCall s)

undefined :: a
undefined =  error "Prelude.undefined"

Ответ 3

Функция "error" - это когда функция получает недопустимый ввод или когда происходит что-то внутреннее, которое никогда не должно происходить (т.е. ошибка). Короче говоря, вызов "error" представляет ошибку - либо в вызывающем, либо вызываемом абоненте.

Константа "undefined" больше предназначена для значений, которые не предполагается использовать, как правило, потому, что они будут заменены чем-то другим или потому, что они phantom значения, используемые для получения определенного тип. (Фактически он реализован как вызов "ошибки".)

Итак, почему у нас есть Control.Exception со всей его привязанностью?

В принципе, "потому что операции ввода-вывода могут генерировать исключения". Вы можете с радостью поговорить с FTP-сервером через TCP-сокет, и вдруг соединение сломается. Результат? Ваша программа выдает исключение. Или у вас может закончиться RAM, или диск может заполнить или что-то еще.

Обратите внимание, что почти все эти вещи не являются вашей ошибкой. Если вы можете предвидеть, что что-то не так, вы должны использовать такие вещи, как Maybe и Either, чтобы обрабатывать его чистым способом. (Например, если вы собираетесь инвертировать матрицу, ну, матрица может быть не обратимой, поэтому вам лучше вернуть Maybe Matrix в качестве результата). Для вещей, которые вы не можете разумно предвидеть (например, какая-то другая программа просто удалила файл, над которым вы пытаетесь работать), исключения - это путь.

Обратите внимание, что Control.Exception содержит множество материалов для обработки исключений, а также просто определение множества разных типов. Меня не волнует, что код, который я вызывал, сделал что-то неправильное и, следовательно, ошибка; Мне все равно хотелось бы сказать клиенту, с которым я только что говорил, что соединение должно быть закрыто, где-то записывать описание в файл журнала и делать другие вещи для очистки, а не просто внезапно запускать мою программу, вы знать, останавливаться.

Ответ 5

Исключения являются законной формой управления потоком. Мне непонятно, почему, при предоставлении инструмента, программисты настаивают на том, что он "только для" определенных случаев и исключает другие возможные применения.

Например, если вы выполняете вычисление обратного отслеживания, вы можете использовать исключения для возврата. В Haskell, вероятно, было бы более распространено использование монады списка для этого, но исключения являются законным способом.