Nous savons tous (ou devrions savoir) que Haskell est paresseux par défaut. Rien n'est évalué tant qu'il ne doit pas l'être. Mais quand doit-on évaluer quelque chose ? Il y a des moments où Haskell doit être strict. Je les appelle "points de rigueur", bien que ce terme particulier ne soit pas aussi répandu que je le pensais. Selon moi :
Réduction (ou évaluation) en Haskell seulement se produit aux points de rigueur.
La question est donc la suivante : quoi, précisément Quels sont les points de rigueur de Haskell ? Mon intuition me dit que main
, seq
/ bang patterns, pattern matching, and any IO
action réalisée par l'intermédiaire de main
sont les principaux points de rigueur, mais je ne sais pas vraiment pourquoi je sais cela.
(Par ailleurs, s'ils ne s'appellent pas "points de rigueur", qu'est-ce que l'on entend par "points de rigueur" ? son ont-ils appelé ?)
J'imagine qu'une bonne réponse comprendra une discussion sur le WHNF, etc. J'imagine également qu'elle pourrait aborder le lambda calcul.
Édition : réflexions supplémentaires sur cette question.
En réfléchissant à cette question, je pense qu'il serait plus clair d'ajouter quelque chose à la définition d'un point de rigueur. Les points de rigueur peuvent avoir des contextes et en faisant varier profondeur (ou rigueur). Revenant à ma définition selon laquelle "la réduction en Haskell ne se produit qu'aux points de rigueur", ajoutons à cette définition cette clause : "un point de rigueur n'est déclenché que lorsque le contexte qui l'entoure est évalué ou réduit".
Permettez-moi donc d'essayer de vous donner le genre de réponse que je souhaite. main
est un point de rigueur. Il est spécialement désigné comme le premier point de rigueur de son contexte : le programme. Lorsque le programme ( main
) est évalué, le point de rigueur de main est activé. La profondeur de main est maximale : elle doit être entièrement évaluée. Main est généralement composé d'actions IO, qui sont également des points de rigueur, dont le contexte est main
.
Essayez maintenant : discutez seq
et le filtrage dans ces termes. Expliquez les nuances de l'application des fonctions : comment est-elle stricte ? En quoi n'est-elle pas stricte ? Qu'en est-il de l'application d'une fonction ? deepseq
? let
y case
déclarations ? unsafePerformIO
? Debug.Trace
? Définitions de premier niveau ? Types de données stricts ? Modèles de Bang ? Etc. Combien de ces éléments peuvent être décrits en termes de séquences ou de modèles ?
10 votes
Votre liste intuitive n'est probablement pas très orthogonale. Je soupçonne que
seq
et la recherche de motifs sont suffisants, le reste étant défini en fonction de ceux-ci. Je pense que le filtrage assure le caractère strict de la colonne vertébrale deIO
par exemple.0 votes
Les primitives, telles que
+
sur les types numériques intégrés imposent également la rigueur, et je suppose qu'il en va de même pour les appels purement FFI.4 votes
Il semble y avoir une confusion entre deux concepts. La correspondance des motifs et les motifs seq et bang sont des moyens par lesquels une expression peut devenir stricte dans ses sous-expressions -- c'est-à-dire que si l'expression supérieure est évaluée, la sous-expression l'est aussi. D'autre part, l'exécution principale d'actions d'entrées-sorties est la façon dont l'évaluation commence . Il s'agit de choses différentes, et les inclure dans la même liste constitue une sorte d'erreur de type.
0 votes
@ChrisSmith Je n'essaie pas de confondre ces deux cas différents ; au contraire, je demande des éclaircissements sur la manière dont ils interagissent. La rigueur se produit d'une manière ou d'une autre, et les deux cas sont des parties importantes, bien que différentes, de la rigueur "se produisant". (et @ monadic : _)
0 votes
Si vous voulez/avez besoin d'espace pour discuter de certains aspects de cette question, sans tenter d'apporter une réponse complète, permettez-moi de vous suggérer d'utiliser les commentaires sur la page mon post /r/haskell pour cette question