What I am trying to build is a generic abstract syntax tree. I assume I have a fixed set of syntactic constructs and I define an F# type for each of them. However the representation of e.g. Identifier names and Expressions should be left open (generic). Thus the code will look something like:
module GAST =
type Declaration<'Name, 'Expr> =
{
id: 'Name
initialValue: 'Expr
}
type Loop<'Name, 'Expr> =
{
condition: 'Expr
body: Statement<'Name, 'Expr> list
}
and Statement<'Name, 'Expr> =
| Declaration of Declaration<'Name, 'Expr>
...
| Loop of Loop<'Name, 'Expr>
...
You see the problem: I have lots of types, all parameterised by 'Name
and 'Expr
. When I want to "instantiate" my generic AST to a specific AST I would have to write a new module where I instantiate each individual type:
module SpecificAST =
type Name = string
type Expr = | Name of Name | Const of int | Addition of Expr * Expr
type Declaration = GAST.Declaration<Name, Expr>
type Loop = GAST.Loop<Name, Expr>
type Statement = GAST.Statement<Name, Expr>
This seems like a lot of code duplication, and cries for something like a module that you could pass types as arguments, because I really just want something like
module SpecificAST = GAST<Name, Expr>
The above is not possible in F#. When searching I found Is it possible to pass parameters to F# modules? but there the issue is different. There is only one type definition but the behaviour of that type's functions is parameterised which can be solved by turning the record type into a class and pass the behaviour as an argument upon instantiation.
I have also seen Can ML functors be fully encoded in .NET (C#/F#)? but I did not see how the various links there could help me.
So my question is this: Given many generic types with the same type parameters. Can I instantiate all at once but avoid an awful code duplication in the instantiating module?