Dans GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Pourquoi le premier n'est-il pas une exception imbriquée?
Dans GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Pourquoi le premier n'est-il pas une exception imbriquée?
error
est un mécanisme spécial et pas vraiment d'exception. Pour de vraies exceptions capturables, voir Error
monade.
(\f g x -> f (g x)) error error ""
se comporte différemment de (.) error error ""
, même si cette fonction est équivalente à (.)
. Cela a peut-être à voir avec les indicateurs d'optimisation avec lesquels Prelude a été compilé.
iterate error "" !! n
et le génial fix error
.
error = error
et programme en conséquence.
Réponses:
La réponse est que c'est la sémantique (quelque peu surprenante) des exceptions imprécises
Lorsqu'on peut montrer que le code pur s'évalue à un ensemble de valeurs exceptionnelles (c'est-à-dire la valeur de error
ou undefined
, et explicitement pas le type d'exceptions générées dans IO ), alors le langage permet de renvoyer n'importe quelle valeur de cet ensemble. Les valeurs exceptionnelles dans Haskell ressemblent plus à NaN
du code à virgule flottante qu'à des exceptions basées sur le flux de contrôle dans les langages impératifs.
Un casse-tête occasionnel, même pour les Haskellers avancés, est un cas tel que:
case x of
1 -> error "One"
_ -> error "Not one"
Puisque le code évalue un ensemble d'exceptions, GHC est libre d'en choisir une. Avec les optimisations activées, vous constaterez peut-être que cela équivaut toujours à "Pas un".
Pourquoi faisons-nous cela? Parce que sinon, nous limiterions trop l'ordre d'évaluation du langage, par exemple, nous devrons fixer un résultat déterministe pour:
f (error "a") (error "b")
par exemple, en exigeant qu'il soit évalué de gauche à droite si des valeurs d'erreur sont présentes. Très peu Haskelly!
Puisque nous ne voulons pas paralyser les optimisations qui peuvent être faites sur notre code juste pour la prise en charge error
, la solution est de spécifier que le résultat est un choix non déterministe parmi l'ensemble des valeurs exceptionnelles: des exceptions imprécises! D'une certaine manière, toutes les exceptions sont renvoyées et une est choisie.
Normalement, vous ne vous souciez pas - une exception est une exception - sauf si vous vous souciez de la chaîne à l'intérieur de l'exception, auquel cas l'utilisation de error
pour déboguer est très déroutante.
Références: Une sémantique pour les exceptions imprécises , Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson. Conception et mise en œuvre des langages de programmation Proc (PLDI'99), Atlanta. ( PDF )
throw
) et avec lesquels vous pouvez lever une exception de manière déterministe throwIO
.
case error "banana" of (x:xs) -> error "bonobo"
peut vous donner * Exception: bonobo
.