Je vois ici des discussions intéressantes sur le typage statique et dynamique. Je préfère généralement le typage statique, en raison de la vérification du type de compilation, du code mieux documenté, etc. Cependant, je suis d'accord pour dire qu'ils encombrent le code si cela est fait comme Java, par exemple.
Je suis donc sur le point de commencer à créer mon propre langage de style fonctionnel, et l'inférence de type est l'une des choses que je souhaite implémenter. Je comprends que c'est un gros sujet, et je n'essaie pas de créer quelque chose qui n'a pas été fait auparavant, juste des inférences de base ...
Des conseils sur ce qu'il faut lire qui m'aidera avec cela? De préférence quelque chose de plus pragmatique / pratique par opposition à des textes de théorie des catégories / théorie des types plus théoriques. S'il y a un texte de discussion sur l'implémentation, avec des structures de données / algorithmes, ce serait tout simplement charmant.
Réponses:
J'ai trouvé les ressources suivantes utiles pour comprendre l'inférence de type, par ordre de difficulté croissante:
Cependant, comme la meilleure façon d'apprendre est de faire, je suggère fortement d'implémenter l'inférence de type pour un langage fonctionnel de jouet en travaillant à travers une tâche à domicile d'un cours de langages de programmation.
Je recommande ces deux devoirs accessibles en ML, que vous pouvez tous deux terminer en moins d'une journée:
Ces devoirs proviennent d'un cours plus avancé:
Implémentation de MiniML
Types polymorphes, existentiels et récursifs (PDF)
Vérification de type bidirectionnelle (PDF)
Sous-typage et objets (PDF)
la source
Il est malheureux qu'une grande partie de la littérature sur le sujet soit très dense. Moi aussi j'étais à ta place. J'ai eu ma première introduction au sujet dans Langages de programmation: applications et interprétation
http://www.plai.org/
Je vais essayer de résumer l'idée abstraite suivie de détails que je n'ai pas trouvés immédiatement évidents. Premièrement, l'inférence de type peut être pensée pour générer puis résoudre des contraintes. Pour générer des contraintes, vous parcourez l'arborescence de syntaxe et générez une ou plusieurs contraintes sur chaque nœud. Par exemple, si le nœud est un
+
opérateur, les opérandes et les résultats doivent tous être des nombres. Un nœud qui applique une fonction a le même type que le résultat de la fonction, et ainsi de suite.Pour un langage sans
let
, vous pouvez résoudre aveuglément les contraintes ci-dessus par substitution. Par exemple:ici, nous pouvons dire que la condition de l'instruction if doit être booléenne, et que le type de l'instruction if est le même que le type de ses clauses
then
andelse
. Puisque nous connaissons1
et2
sommes des nombres, par substitution, nous savons que l'if
énoncé est un nombre.Là où les choses deviennent désagréables, et ce que je n'ai pas pu comprendre pendant un moment, c'est que:
Ici, nous sommes liés
id
à une fonction qui renvoie tout ce que vous avez passé, autrement connu sous le nom de fonction d'identité. Le problème est que le type de paramètre de la fonctionx
est différent à chaque utilisation deid
. La secondeid
est une fonction de typea -> a
, oùa
peut être n'importe quoi. Le premier est de type(a -> a) -> (a -> a)
. Ceci est connu sous le nom de let-polymorphisme. La clé est de résoudre les contraintes dans un ordre particulier: commencez par résoudre les contraintes pour la définition deid
. Ce seraa -> a
. Ensuite, des copies fraîches et séparées du type deid
peuvent être substituées dans les contraintes pour chaque lieuid
, par exemplea2 -> a2
eta3 -> a3
.Cela n'a pas été facilement expliqué dans les ressources en ligne. Ils mentionneront l'algorithme W ou M, mais pas comment ils fonctionnent en termes de résolution des contraintes, ou pourquoi il ne barf sur let-polymorphisme: chacun de ces algorithmes applique un ordre sur la résolution des contraintes.
J'ai trouvé cette ressource extrêmement utile pour lier les algorithmes W, M et le concept général de génération et de résolution de contraintes. C'est un peu dense, mais meilleur que beaucoup:
http://www.cs.uu.nl/research/techreps/repo/CS-2002/2002-031.pdf
La plupart des autres articles sont également intéressants:
http://people.cs.uu.nl/bastiaan/papers.html
J'espère que cela aidera à clarifier un monde quelque peu trouble.
la source
Outre Hindley Milner pour les langages fonctionnels, une autre approche populaire de l'inférence de type pour le langage dynamique est
abstract interpretation
.L'idée de l'interprétation abstraite est d'écrire un interpréteur spécial pour le langage, au lieu de garder un environnement de valeurs concrètes (1, false, fermeture), cela fonctionne sur des valeurs abstraites, aka types (int, bool, etc.). Puisqu'il interprète le programme sur des valeurs abstraites, c'est pourquoi on l'appelle interprétation abstraite.
Pysonar2 est une implémentation élégante d'interprétation abstraite pour Python. Il est utilisé par Google pour analyser les projets Python. Fondamentalement, il utilise
visitor pattern
pour envoyer l'appel d'évaluation au nœud AST concerné. La fonction visiteurtransform
accepte lecontext
dans lequel le nœud actuel sera évalué et renvoie le type de nœud actuel.la source
Types et langages de programmation par Benjamin C. Pierce
la source
Lambda l'ultime, à partir d' ici .
la source