J'aimerais en savoir plus sur la programmation concaténative à travers la création d'un petit langage simple, basé sur la pile et suivant le paradigme concaténatif.
Malheureusement, je n'ai pas trouvé beaucoup de ressources concernant les langages concaténatifs et leur mise en œuvre, alors excusez-moi à l'avance pour ma possible naïveté.
J'ai donc défini mon langage comme une simple séquence de concaténation de fonctions, représentée dans l'AST sous forme de liste:
data Operation
= Concat [Operation]
| Quotation Operation
| Var String
| Lit Literal
| LitOp LiteralOperation
data Literal
= Int Int
| Float Float
data LiteralOperation
= Add | Sub | Mul | Div
Le programme suivant, 4 2 swap dup * +
(correspondant à 2 * 2 + 4
) une fois analysé, donnera l'AST suivant:
Concat [Lit (Int 4), Lit (Int 2), Var "swap", Var "dup", LitOp Mul, LitOp Add]
Maintenant, je dois déduire et vérifier les types.
J'ai écrit ce système de type:
data Type
= TBasic BasicType -- 'Int' or 'Float'
| TVar String -- Variable type
| TQuoteE String -- Empty stack, noted 'A'
| TQuote String Type -- Non empty stack, noted 'A t'
| TConc Type Type -- A type for the concatenation
| TFun Type Type -- The type of functions
C'est là que ma question entre en jeu, car je ne sais pas quel type déduire de cette expression. Le type qui en résulte est évident, Int
mais je ne sais pas comment vérifier entièrement ce programme au niveau du type.
Au début, comme vous pouvez le voir ci-dessus, j'avais pensé à un TConc
type qui représente la concaténation de la même manière que le TFun
type représente une fonction, car à la fin la séquence de concaténation forme une fonction unique.
Une autre option, que je n'ai pas encore explorée, serait d'appliquer la règle d'inférence de composition de fonction à chaque élément de cette séquence d'expression. Je ne sais pas comment cela fonctionnerait avec la pile.
La question est la suivante: comment procéder? Quel algorithme utiliser et quelle approche au niveau du type devrait être préférée?