Tout comme le titre l'indique: quelles garanties existe-t-il pour qu'une unité de retour de fonction Haskell soit évaluée? On pourrait penser qu'il n'est pas nécessaire d'exécuter une sorte d'évaluation dans un tel cas, le compilateur pourrait remplacer tous ces appels par une ()
valeur immédiate à moins que des demandes explicites de rigueur ne soient présentes, auquel cas le code pourrait avoir à décider s'il devrait retour ()
ou bas.
J'ai expérimenté cela dans GHCi, et il semble que le contraire se produise, c'est-à-dire qu'une telle fonction semble être évaluée. Un exemple très primitif serait
f :: a -> ()
f _ = undefined
L'évaluation f 1
renvoie une erreur en raison de la présence de undefined
, donc une évaluation se produit définitivement. Cependant, la profondeur de l'évaluation n'est pas claire; parfois, il semble aller aussi loin qu'il est nécessaire d'évaluer tous les appels aux fonctions renvoyées ()
. Exemple:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Ce code boucle indéfiniment s'il est présenté avec g (let x = 1:x in x)
. Mais alors
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
peut être utilisé pour montrer que les h (f 1)
retours ()
, dans ce cas, toutes les sous-expressions unitaires ne sont pas évaluées. Quelle est la règle générale ici?
ETA: bien sûr, je connais la paresse. Je demande ce qui empêche les rédacteurs du compilateur de rendre ce cas particulier encore plus paresseux que d'habitude.
ETA2: résumé des exemples: GHC semble traiter ()
exactement comme tout autre type, c'est-à-dire comme s'il y avait une question sur la valeur régulière occupant le type qui devrait être renvoyée par une fonction. Le fait qu'il n'existe qu'une seule de ces valeurs ne semble pas être (ab) utilisé par les algorithmes d'optimisation.
ETA3: quand je dis Haskell, je veux dire Haskell tel que défini par le rapport, pas Haskell-le-H-dans-GHC. Semble être une hypothèse qui n'est pas partagée aussi largement que je l'imaginais (qui était «à 100% des lecteurs»), ou j'aurais probablement pu formuler une question plus claire. Néanmoins, je regrette d'avoir changé le titre de la question, car elle demandait à l'origine quelles garanties existe pour une telle fonction appelée.
ETA4: il semblerait que cette question ait suivi son cours, et je la considère comme sans réponse. (Je cherchais une fonction de `` question proche '' mais je n'ai trouvé que `` répondre à votre propre question '' et comme il ne peut pas être répondu, je n'ai pas suivi cette voie.) Personne n'a soulevé quoi que ce soit du rapport qui déciderait de toute façon , que je suis tenté d'interpréter comme une réponse forte mais non définitive «aucune garantie pour la langue en tant que telle». Tout ce que nous savons, c'est que la mise en œuvre actuelle du GHC n'ignorera pas l'évaluation d'une telle fonction.
J'ai rencontré le problème réel lors du portage d'une application OCaml vers Haskell. L'application d'origine avait une structure mutuellement récursive de nombreux types, et le code a déclaré un certain nombre de fonctions appelées assert_structureN_is_correct
N dans 1..6 ou 7, chacune renvoyant unité si la structure était effectivement correcte et lançant une exception si elle n'était pas . De plus, ces fonctions se sont appelées l'une l'autre en décomposant les conditions d'exactitude. À Haskell, cela est mieux géré en utilisant la Either String
monade, donc je l'ai transcrite de cette façon, mais la question en tant que problème théorique est restée. Merci pour toutes les contributions et réponses.
f 1
est "remplacé" par undefined
dans tous les cas.
... -> ()
peut 1) se terminer et retourner ()
, 2) se terminer avec une erreur d'exception / d'exécution et ne rien retourner, ou 3) diverger (récursion infinie). GHC n'optimise pas le code en supposant que 1) peut se produire: s'il f 1
est demandé, il ne saute pas son évaluation et son retour ()
. La sémantique de Haskell consiste à l'évaluer et à voir ce qui se passe entre 1,2,3.
()
(ni le type ni la valeur) dans cette question. Toutes les mêmes observations se produisent si vous remplacez () :: ()
par, disons, 0 :: Int
partout. Ce ne sont que de vieilles conséquences ennuyeuses d'une évaluation paresseuse.
()
type, ()
et undefined
.
h1::()->() ; h1 () = ()
eth2::()->() ; h2 _ = ()
. Exécutez les deuxh1 (f 1)
eth2 (f 1)
, et voyez que seul le premier l'exige(f 1)
.