Як працюють винятки в Haskell?


86

У GHCi:

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

Чому перший не є вкладеним винятком?


9
Це перетворення, яке дозволено здійснити GHC: "Я - Компілятор, який діє сам, і всі _ | _ схожі на мене". Ви вимагаєте деталей реалізації, які змушують ці два рядки компілюватись по-різному?
shachaf

3
errorє особливим і насправді не механізмом винятків. Для справжніх, виловлюваних винятків див Error. Монаду .
Cat Plus Plus

1
Наприклад, зауважте, що вона (\f g x -> f (g x)) error error ""поводиться інакше (.) error error "", ніж ця функція еквівалентна (.). Можливо, це пов’язано з прапорами оптимізації, з якими було скомпоновано Prelude.
shachaf

5
Також iterate error "" !! nі дивовижний fix error.
Вітус,

9
Я завжди вдаю це error = errorі програмую відповідно.
Габріель Гонсалес,

Відповіді:


101

Відповідь полягає в тому, що це (дещо дивно) семантика неточних винятків

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

Час від часу навіть для просунутих хаскелерів є такі випадки, як:

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

Оскільки код оцінює безліч винятків, GHC може вільно вибрати такий. Якщо ввімкнено оптимізацію, цілком можливо, це завжди оцінюється як "Не одна".

Чому ми це робимо? Оскільки інакше ми надмірно обмежимо порядок оцінки мови, наприклад, нам доведеться зафіксувати детермінований результат для:

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

наприклад, вимагаючи, щоб воно обчислювалось зліва направо, якщо наявні значення помилок. Дуже не-Хаскеллі!

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

Зазвичай вас це не хвилює - виняток є винятком - якщо ви не дбаєте про рядок усередині винятку, і в цьому випадку використання errorдля налагодження дуже заплутане.


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


2
Я розумію, що GHC обрав один із будь-яких винятків, з якими можна зіткнутися. Але у вашому прикладі "case" виняток "Not one" не можна зустріти для введення 1, тому я все одно класифікую це як помилку.
Пікер,

8
Усунення мертвого коду @Peaker - оптимізатору не потрібно дивитись на x, щоб побачити, що результатом є помилка, усі гілки видають "однакове" значення, тому він може повністю ігнорувати введене значення. Не помилка, за неточними винятками!
Дон Стюарт,

1
@lpsmith: Я думаю, що всі типи винятків є неточними (коли їх видають за допомогою throw), і що ви можете детерміновано кинути виняток за допомогою throwIO.
FunctorSalad

4
@Peaker Я думаю, ти маєш рацію. Я не думаю, що ghc повинен оптимізувати цей вираз, якщо вони хочуть грати за правилами, викладеними в неточному звіті.
серпень

3
Неточний виняток , здається, говорить про те, що якщо перевірка справи є значенням помилки, тоді значення помилок з гілок можуть бути повернуті. Так case error "banana" of (x:xs) -> error "bonobo"може дати вам * Exception: bonobo.
Ben Millwood
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.