Как работают исключения в Haskell?

В GHCi:

Prelude> error (error "")
*** Exception: 
Prelude> (error . error) ""
*** Exception: *** Exception: 

Почему не первое вложенное исключение?

Ответ 1

Ответ заключается в том, что это (несколько удивительная) семантика неточных исключений

Когда чистый код может быть показан для вычисления в набор исключительных значений (т.е. значение error или undefined и явно не вид исключений сгенерированных в IO), то язык позволяет вернуть любое значение этого набора. Исключительные значения в Haskell больше похожи на NaN в коде с плавающей запятой, а не на исключениях на основе потока управления на императивных языках.

Случайный доступ для даже продвинутых Haskellers - это случай, например:

 case x of
   1 -> error "One"
   _ -> error "Not one"

Так как код оценивает набор исключений, GHC может выбрать его. С оптимизацией, вы можете найти, что это всегда оценивается как "Не один".

Зачем мы это делаем? Потому что иначе мы бы слишком ограничивали порядок оценки языка, например. мы должны были бы исправить детерминированный результат для:

 f (error "a") (error "b")

например, требуя, чтобы он оценивался слева направо, если присутствуют значения ошибок. Очень не-Хаскелли!

Поскольку мы не хотим наносить ущерб оптимизациям, которые могут быть сделаны на нашем коде только для поддержки error, решение заключается в том, чтобы указать, что результат является недетерминированным выбором из множества исключительных значений: неточные исключения! В некотором смысле все исключения возвращаются, и один выбирается.

Как правило, вам все равно - исключение - исключение - если только вы не заботитесь о строке внутри исключения, и в этом случае использование error для отладки очень сбивает с толку.


Ссылки: Семантика для неточных исключений, Саймон Пейтон Джонс, Аластер Рид, Тони Хоар, Саймон Марлоу, Фергус Хендерсон. Проектирование и внедрение языков программирования Proc (PLDI'99), Атланта. (PDF)