命名空间由名称和类列表组成 类由名称和方法列表组成 方法由名称、返回类型和参数列表组成 参数由类型和名称组成 这个简单的程序示例语:
您还需要类型系统的类型定义,这实际上是联合类型有价值的唯一地方:
type Type = Void | Int | String
因此,您的语言中的类型可以是 int 或 string 或 void,但不能是空值(例如 null),并且不能超过这些选项中的一个。
命名空间的类型可以是完全匿名的,如下所示:
string * (string * (Type * string * (Type * string) list) list) list
您可以像这样定义示例命名空间:
"ns", ["cls1", [Void, "m1", []]
"cls2", [Void, "m2", [Int, "i"; String, "j"]]]
在实践中,您可能希望能够将命名空间放入其他命名空间并将类放入类中,这样您就可以将代码演变成如下内容:
type Type =
| Void
| Int
| String
| Class of Map<string, Type> * Map<string, Type * (Type * string) list>
type Namespace =
| Namespace of string * Namespace list * Map<string, Type>
Namespace("ns", [],
Map
[ "cls1", Class(Map[], Map["m1", (Void, [])])
"cls2", Class(Map[], Map["m2", (Void, [Int, "i"; String, "j"])])])
匿名类型很好,只要它们不会造成混淆。根据经验,如果您有两个或三个字段并且它们属于不同类型(如此处的“方法”),那么元组就可以了。如果有更多字段或具有相同类型的多个字段,那么是时候切换到记录类型了。
因此,在这种情况下,您可能需要为方法引入记录类型:
type Method =
{ ReturnType: Type
Arguments: (Type * string) list }
and Type =
| Void
| Int
| String
| Class of Map<string, Type> * Map<string, Method>
type Namespace =
| Namespace of string * Namespace list * Map<string, Type>
Namespace("ns", [],
Map
[ "cls1", Class(Map[], Map["m1", { ReturnType = Void; Arguments = [] }])
"cls2", Class(Map[], Map["m2", { ReturnType = Void; Arguments = [Int, "i"; String, "j"] }])])
也许还有一个辅助函数来构建这些记录:
let Method retTy name args =
name, { ReturnType = retTy; Arguments = args }
Namespace("ns", [],
Map
[ "cls1", Class(Map[], Map[Method Void "m1" []])
"cls2", Class(Map[], Map[Method Void "m2" [Int, "i"; String, "j"]])])