一个命名空间包含名称和类 一类由名称的列表和方法列表 方法由名称,返回类型和参数列表的 参数由一个类型的和在这个简单的语言编写的程序的名称 例子:
您还需要一个类型定义为你的类型系统,实际上就是联合类型是宝贵的唯一的地方:
type Type = Void | Int | String
所以你的语言中的一个类型是一个int或一个字符串或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"]])])
嗯,所以两者的混合,我有点期待.. –
我倾向于用元组来使用DU。它们更容易编写,但可能会让人困惑,因为你不仅仅有几个参数,而且你依赖文档来告诉你每个参数的用途。例如,对于Method中的Parameters,您可以改为说'Parameters:(String * TypeName)列表选项',这显然是每个元组表示的项目。但是,如果您也是使用String作为类型,而不是TypeName,并且使用了'(String * String)',那么需要记录来理解每个对象的用途。 –
我通常会尝试在可读性方面犯错,所以我想我会坚持记录而不是元组。 –