扩展相互递归的函子

时间:2018-09-26 07:58:10

标签: recursion ocaml functor

我正在编写一个编译器,需要表示一些共同递归的结构,这些结构取决于表示表达式的数据结构。在编译开始时,不会键入我的表达式,但稍后会输入它们。

我编写了以下函子,以便能够在此过程中重用代码:

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种中间表示形式,一种使用无类型的表达式,另一种使用类型的表达式。

我现在想编写一个打印模块,并且希望以与前面相同的方式分解代码。以下是我未成功的尝试,我不了解如何正确扩展TExpUTexp。 更具体地说,我不知道如何共享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

的问题

1 个答案:

答案 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

我希望其余的错误也会随之而来,因为有可能共享正确的类型相等性。