Je travaille sur un compilateur pour un langage concaténatif et je voudrais ajouter un support d'inférence de type. Je comprends Hindley – Milner, mais j'ai appris la théorie des types au fur et à mesure, donc je ne sais pas comment l'adapter. Le système suivant est-il solide et inférable?
Un terme est un littéral, une composition de termes, une citation d'un terme ou une primitive.
Tous les termes désignent des fonctions. Pour deux fonctions et , , c'est-à-dire que la juxtaposition désigne la composition inverse. Les littéraux désignent les fonctions niladiques.e 2 e 1
Les termes autres que composition ont des règles de type de base:
Les règles d'application sont particulièrement absentes, car les langues concaténatives en sont dépourvues.
Un type est soit un littéral, une variable de type, soit une fonction de piles en piles, où une pile est définie comme un tuple imbriqué à droite. Toutes les fonctions sont implicitement polymorphes par rapport au «reste de la pile».
C'est la première chose qui semble suspecte, mais je ne sais pas exactement ce qui ne va pas.
Pour faciliter la lisibilité et réduire les parenthèses, je suppose que dans les schémas de types. Je vais également utiliser une lettre majuscule pour une variable désignant une pile, plutôt qu'une seule valeur.
Il existe six primitives. Les cinq premiers sont assez inoffensifs. dup
prend la valeur la plus élevée et en produit deux copies. swap
change l'ordre des deux premières valeurs. pop
ignore la valeur supérieure. quote
prend une valeur et produit une citation (fonction) qui la renvoie. apply
applique un devis à la pile.
Le dernier combinateur compose
,, doit prendre deux citations et retourner le type de leur concaténation, c'est-à-dire . Dans le langage concaténatif de type statique Cat , le type de est très simple.compose
Cependant, ce type est trop restrictif: il nécessite que la production de la première fonction corresponde exactement à la consommation de la seconde. En réalité, vous devez assumer des types distincts, puis les unifier. Mais comment écririez-vous ce type?
Si vous laissez dénoter une différence de deux types, alors je pense que vous pouvez écrire le type de correctement.compose
Ceci est encore relativement simple: compose
prend une fonction et une . Son résultat consomme au sommet de la consommation de non produite par , et produit au sommet de la production de non consommée par . Cela donne la règle de la composition ordinaire.f 2 : D → E B f 2 f 1 D f 1 f 2
Cependant, je ne sais pas si cet hypothétique correspond en fait à quelque chose, et je le poursuis en rond depuis assez longtemps pour que je pense avoir pris un mauvais virage. Serait-ce une simple différence de tuples?
Y a-t-il quelque chose d'horriblement cassé que je ne vois pas, ou suis-je sur quelque chose comme la bonne voie? (J'ai probablement quantifié à tort certaines de ces choses et j'apprécierais également les correctifs dans ce domaine.)
compose
est trop restrictive? J'ai l'impression que c'est bien comme ça. (par exemple la restriction pourrait être gérée par unification comme pour une application similaire dans le λ-calcul)twice
défini commedup compose apply
, qui prend une citation et l'applique deux fois.[1 +] twice
c'est bien: vous composez deux fonctions de type . Mais ce n'est pas le cas: si , le problème est que , donc l'expression est interdite même si elle doit être valide et avoir taper . La solution est bien sûr de mettre le qualificatif au bon endroit, mais je me demande principalement comment écrire réellement le type de sans définition circulaire. ∀ A b .[pop] twice
A ≠ Acompose
Réponses:
Le type de rang 2 suivant semble être suffisamment général. Il est beaucoup plus polymorphe que le type proposé dans la question. Ici, la quantification variable sur des morceaux contigus de pile, qui capture les fonctions multi-arguments.
Les lettres grecques sont utilisées pour les autres variables de la pile à des fins de clarté uniquement.
Il exprime les contraintes que la pile de sortie du premier élément de la pile doit être la même que la pile d'entrée du deuxième élément. Instancier de manière appropriée la variable pour les deux arguments est le moyen de faire fonctionner correctement les contraintes, plutôt que de définir une nouvelle opération, comme vous le proposez dans la question.B
La vérification de type des types de rang 2 est indécidable en général, je pense, bien qu'un travail ait été fait qui donne de bons résultats dans la pratique (pour Haskell):
La règle de type pour la composition est simplement:
Pour que le système de typage fonctionne en général, vous avez besoin de la règle de spécialisation suivante:
la source
dup +
devrait avoir le type car a le type . Mais l'inférence de type en l'absence d'annotations est une exigence absolue, donc je dois clairement revenir à la planche à dessin. J'ai une idée pour une autre approche à poursuivre, cependant, et bloguerai à ce sujet si cela fonctionne.+
dup +
, car cela n'utilise pas la composition, comme vous l'avez défini ci-dessus.[dup] [+] compose
. Mais j'ai lu comme ; dites ; alors vous avez et non . L'imbrication n'est pas correcte, sauf si vous retournez la pile pour que le haut soit le dernier élément (le plus profond imbriqué). B × α B = ι × ι ( ι × ι ) × α ι × ( ι × α )