我正在编写一个编译器,需要表示一些共同递归的结构,这些结构取决于表示表达式的数据结构。在编译开始时,不会键入我的表达式,但稍后会输入它们。
我编写了以下函子,以便能够在此过程中重用代码:
module type Exp = sig
type t
end
module type IR = sig
type exp
type ty =
| Unknown
| Typed of exp
type exp_descr =
| Leaf
| Node of exp
end
module MyIR (E: Exp) = struct
type ty =
| Unknown
| Typed of E.t
type exp_descr =
| Leaf
| Node of E.t
type exp = E.t
end
module UntypedExp (TD: IR) : (Exp with type t = TD.exp_descr) = struct
type t = TD.exp_descr
end
module TypedExp (TD: IR) : Exp = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
module rec UTExp : Exp = UntypedExp(UTIR)
and UTIR : IR = MyIR(UTExp)
module rec TExp : Exp = TypedExp(TIR)
and TIR : IR = MyIR(TExp)
我现在有2种中间表示形式,一种使用无类型的表达式,另一种使用类型的表达式。
我现在想编写一个打印模块,并且希望以与前面相同的方式分解代码。以下是我未成功的尝试,我不了解如何正确扩展TExp
和UTexp
。
更具体地说,我不知道如何共享TypedExp
中定义的字段构造函数。
module type ExpPrint = sig
type t
val string_of_t: t -> string
end
module type IRPrint = sig
include IR
val string_of_ty: ty -> string
val string_of_exp_descr: exp_descr -> string
val string_of_exp: exp -> string
end
module MyExpPrint (R: IR) (E: ExpPrint with type t = R.exp) : (IRPrint with type exp := R.exp and type exp_descr := R.exp_descr and type ty := R.ty) = struct
open R
let string_of_exp = E.string_of_t
let string_of_ty = function
| R.Unknown -> "Unknown"
| Typed e -> "Typed: " ^ string_of_exp e
let string_of_exp_descr = function
| R.Leaf -> "Leaf"
| Node e -> "Node: " ^ string_of_exp e
end
module UTExpPrint (E : module type of UTExp) (R: IRPrint with type exp = E.t) : (ExpPrint with type t := R.exp_descr) = struct
open E
let string_of_t = R.string_of_exp_descr
end
module TExpPrint (E : module type of TExp) (R: IRPrint with type exp = E.t) : (ExpPrint with type t := R.exp) = struct
open E
let string_of_t e = R.string_of_exp_descr e.TExp.descr ^ " " ^ R.string_of_ty e.ty
end
编辑:修复了MyExpPrint
答案 0 :(得分:5)
由于模块类型Exp
被定义为
module type Exp = sig type t end
任何形式为M: Exp
的签名约束都使M
无法使用,因为它隐藏了有关M的所有信息,除了抽象类型M.t的存在。由于抽象类型与外界之间没有功能,因此该抽象类型不可用。
例如,此模块定义定义了一个类型,并立即将其隐藏在外面:
module TypedExp (TD: IR) : Exp = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
您想要的只是
module TypedExp (TD: IR) = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
如果您真的想添加签名约束,那么正确的选择就是
module TypedExp (TD: IR): sig
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
= struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
请注意,由于两个原因,我没有使用Exp with type t = ...
:首先,with
约束不能定义新类型。其次,Exp with type t = ...
只是编写sig type t = ... end
的一种复杂方法。
这是代码的核心问题:它隐藏了所有可能有意义地操纵您定义的类型的信息。
例如,在删除函子结果上的签名约束后,将签名固定在递归模块约束中,将IRprint的签名简化为
module type IRPrint = sig
type ty
type exp_descr
type exp
val string_of_ty: ty -> string
val string_of_exp_descr: exp_descr -> string
val string_of_exp: exp -> string
end
然后可以使用
修复函子TExpPrint
module TExpPrint
(E : module type of TExp)
(R: IRPrint with type exp_descr = TIR.exp_descr
and type exp = E.t
and type ty = TIR.ty)
=
struct
open E
let string_of_t e =
R.string_of_exp_descr e.E.descr ^ " " ^ R.string_of_ty e.ty
end
我希望其余的错误也会随之而来,因为有可能共享正确的类型相等性。