W GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Dlaczego pierwszy nie jest zagnieżdżonym wyjątkiem?
W GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Dlaczego pierwszy nie jest zagnieżdżonym wyjątkiem?
error
jest specjalny i nie jest tak naprawdę mechanizmem wyjątków. Aby poznać prawdziwe, możliwe do złapania wyjątki, zobacz monadę Error
.
(\f g x -> f (g x)) error error ""
zachowuje się inaczej niż (.) error error ""
, mimo że ta funkcja jest równoważna (.)
. Może ma to związek z flagami optymalizacji, z którymi skompilowano program Prelude.
iterate error "" !! n
niesamowite fix error
.
error = error
i odpowiednio programuję.
Odpowiedzi:
Odpowiedź brzmi, że jest to (nieco zaskakująca) semantyka nieprecyzyjnych wyjątków
Gdy można wykazać, że czysty kod oblicza zbiór wyjątkowych wartości (tj. Wartość error
lub undefined
, a wyraźnie nie rodzaj wyjątków wygenerowanych w IO ), wówczas język zezwala na zwrócenie dowolnej wartości tego zestawu. Wyjątkowe wartości w Haskell są bardziej jak NaN
w kodzie zmiennoprzecinkowym, a nie w wyjątkach opartych na przepływie sterowania w językach imperatywnych.
Od czasu do czasu nawet zaawansowanych Haskellerów może się zdarzyć:
case x of
1 -> error "One"
_ -> error "Not one"
Ponieważ kod ocenia się jako zestaw wyjątków, GHC może wybrać jeden. Przy włączonych optymalizacjach może się okazać, że zawsze daje to wynik „Brak”.
Dlaczego to robimy? Ponieważ w przeciwnym razie nadmiernie ograniczylibyśmy kolejność ocen języka, np. Musielibyśmy ustalić deterministyczny wynik dla:
f (error "a") (error "b")
na przykład wymagając, aby był oceniany od lewej do prawej, jeśli obecne są wartości błędów. Bardzo nie-haskelly!
Ponieważ nie chcemy paraliżować optymalizacji, które można wykonać w naszym kodzie tylko w celu wsparcia error
, rozwiązaniem jest określenie, że wynik jest niedeterministycznym wyborem z zestawu wyjątkowych wartości: nieprecyzyjne wyjątki! W pewnym sensie wszystkie wyjątki są zwracane i jeden jest wybierany.
Zwykle nic Cię to nie obchodzi - wyjątek jest wyjątkiem - chyba że zależy Ci na ciągu znaków wewnątrz wyjątku, w którym to przypadku użycie error
do debugowania jest bardzo mylące.
Odniesienia: semantyka nieprecyzyjnych wyjątków , Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson. Projektowanie i wdrażanie języków programowania proc (PLDI'99), Atlanta. ( PDF )
throw
) i można deterministycznie zgłosić wyjątek z throwIO
.
case error "banana" of (x:xs) -> error "bonobo"
mogę ci dać * Exception: bonobo
.