Vorrei saperne di più sulla programmazione concatenativa attraverso la creazione di un piccolo linguaggio semplice, basato sullo stack e seguendo il paradigma concatenativo.
Sfortunatamente, non ho trovato molte risorse relative ai linguaggi concatenativi e alla loro implementazione, quindi scusami in anticipo per la mia possibile ingenuità.
Ho quindi definito il mio linguaggio come una semplice sequenza di concatenazione di funzioni, rappresentata nell'AST come un elenco:
data Operation
= Concat [Operation]
| Quotation Operation
| Var String
| Lit Literal
| LitOp LiteralOperation
data Literal
= Int Int
| Float Float
data LiteralOperation
= Add | Sub | Mul | Div
Il seguente programma, 4 2 swap dup * +
(corrispondente a 2 * 2 + 4
) una volta analizzato, fornirà il seguente AST:
Concat [Lit (Int 4), Lit (Int 2), Var "swap", Var "dup", LitOp Mul, LitOp Add]
Ora devo dedurre e controllare i tipi.
Ho scritto questo tipo di sistema:
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
È qui che arriva la mia domanda, perché non so quale tipo dedurre da quell'espressione. Il tipo risultante è ovvio, lo è Int
, ma non so come controllare completamente questo programma a livello di tipo.
All'inizio, come puoi vedere sopra, avevo pensato a un TConc
tipo che rappresenta la concatenazione allo stesso modo in cui il TFun
tipo rappresenta una funzione, perché alla fine la sequenza di concatenazione forma una funzione unica.
Un'altra opzione, che non ho ancora esplorato, sarebbe quella di applicare la regola di inferenza della composizione della funzione a ciascun elemento di questa sequenza di espressioni. Non so come funzionerebbe con lo stack-based.
La domanda è così: come lo facciamo? Quale algoritmo da usare e quale approccio a livello di tipo dovrebbe essere preferito?