Oto transformacja, której GHC może dokonać: „Jestem Kompilatorem, który działa samodzielnie i wszystkie _ | _ są do mnie podobne”. Czy pytasz o szczegóły implementacji, które powodują, że te dwie linie kompilują się inaczej?
shachaf
3
errorjest specjalny i nie jest tak naprawdę mechanizmem wyjątków. Aby poznać prawdziwe, możliwe do złapania wyjątki, zobacz monadę Error.
Cat Plus Plus,
1
Zauważ na przykład, że (\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.
shachaf
5
A także iterate error "" !! nniesamowite fix error.
Vitus
9
Zawsze to udaję error = errori odpowiednio programuję.
Gabriel Gonzalez
Odpowiedzi:
101
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ść errorlub 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 NaNw 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 of1 -> 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 errordo 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 )
Rozumiem, że GHC wybiera jeden z wyjątków, które można napotkać. Ale w twoim przykładzie „przypadku” wyjątek „Brak” nie może zostać napotkany dla wejścia równego 1, więc nadal klasyfikuję to jako błąd.
Peaker
8
@Peaker dead code elim - optymalizator nie musi patrzeć na x, aby zobaczyć, że wynikiem jest błąd, wszystkie gałęzie generują „tę samą” wartość, więc może całkowicie zignorować wartość wejściową. To nie błąd, z nieprecyzyjnymi wyjątkami!
Don Stewart
1
@lpsmith: Myślę, że wszystkie typy wyjątków są nieprecyzyjne (gdy są wyrzucane przy użyciu throw) i można deterministycznie zgłosić wyjątek z throwIO.
FunctorSalad
4
@Peaker Myślę, że masz rację. Myślę, że ghc nie powinien optymalizować tego wyrażenia, jeśli chce grać według zasad przedstawionych w nieprecyzyjnym dokumencie dotyczącym wyjątków.
sierpień
3
Co papier wyjątki nieprecyzyjne nie wydają się powiedzieć to, że jeśli sprawa scrutinee jest wartością błędu mogą być zwrócone następnie wartości błędu z gałęzi. Więc case error "banana" of (x:xs) -> error "bonobo"mogę ci dać * Exception: bonobo.
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
niesamowitefix 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
lubundefined
, 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 jakNaN
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 )
źródło
throw
) i można deterministycznie zgłosić wyjątek zthrowIO
.case error "banana" of (x:xs) -> error "bonobo"
mogę ci dać* Exception: bonobo
.