OCaml使用在仿函数外定义的签名来限制生成模块的可见性

OCaml使用在仿函数外定义的签名来限制生成模块的可见性

问题描述:

我试图编写一个函数,它需要一对有序的东西并生成另一个有序的东西(按照字典顺序定义)。OCaml使用在仿函数外定义的签名来限制生成模块的可见性

但是,我想要得到的“有序类型”是抽象的,而不是OCaml元组。

这很容易处理内联/匿名签名。

(* orderedPairSetInlineSig.ml *) 

module type ORDERED_TYPE = sig 
    type t 
    val compare : t -> t -> int 
end 

module MakeOrderedPairSet (X : ORDERED_TYPE) : 
    sig 
    type t 
    val get_fst : t -> X.t 
    val get_snd : t -> X.t 
    val make : X.t -> X.t -> t 
    val compare : t -> t -> int 
    end = struct 
    type t = X.t * X.t 

    let combine_comparisons fst snd = 
     if fst = 0 then snd else fst 

    let compare (x, y) (a, b) = 
     let cmp = X.compare x a in 
     let cmp' = X.compare y b in 
     combine_comparisons cmp cmp' 

    let get_fst ((x, y) : t) = x 

    let get_snd ((x, y) : t) = y 

    let make x y = (x, y) 
    end 

我想给我的匿名签名名称,如ORDERED_PAIR_SET_TYPE和移动它的MakeOrderedPairSet的定义之外,像这样(警告:不是语法有效):与el是一个抽象类型

(* orderedPairSet.ml *) 

module type ORDERED_TYPE = sig 
    type t 
    val compare : t -> t -> int 
end 

module type ORDERED_PAIR_SET_TYPE = sig 
    type t 
    type el 

    val get_fst : t -> el 
    val get_snd : t -> el 
    val make : el -> el -> t 

    val compare : t -> t -> int 
end 

module MakeOrderedPairSet (X : ORDERED_TYPE) : 
    (ORDERED_PAIR_SET_TYPE with type el = X.t) = struct 
    type t = X.t * X.t 

    let combine_comparisons fst snd = 
     if fst = 0 then snd else fst 

    let compare (x, y) (a, b) = 
     let cmp = X.compare x a in 
     let cmp' = X.compare y b in 
     combine_comparisons cmp cmp' 

    let get_fst ((x, y) : t) = x 

    let get_snd ((x, y) : t) = y 

    let make x y = (x, y) 
    end 

在我试图绑定到MakeOrderedPairSet正文内的X.t的签名中。

但是,我无法弄清楚如何将所有东西放在一起。

(ORDERED_PAIR_SET_TYPE with type el = X.t)是我能想到的最明显的方式,就是说“给我一个和这个一样的签名,但是用一个抽象类型替换为一个抽象类型(或者在本例中是不同的抽象)”。但是,这种情况在语法上不合法(因为括号)。关闭括号并不会产生有效的“模块语言级表达式”;我把它留下了,因为我认为这让我的意图更加明显。

所以...你如何使用命名的签名来限制[函数产生的模块]/[参数化模块]的可见性?

+2

一旦缺乏定义'type el = Xt'固定,你的例子适用于我(有和没有括号)? – octachron

+0

@ octachron yes ...在方法的主体中添加一个明确的'type el = Xt'确实使OCaml程序有效,但它也向接口添加了一个新的导出类型...所以它不完全等效在functor定义之外的第一个例子中“移动”匿名接口。 –

如果你不希望添加el到模块的出口则有两种方式:

  1. 使用替代约束:

    ORDERED_PAIR_SET_TYPE with type el := X.t 
    

    这将删除的来自签名的el规范。

  2. 使用参数化签名。不幸的是,这是不是在OCaml中直接表达,但需要一些额外的函子体操在你签字的定义:

    module SET_TYPE (X : ORDERED_TYPE) = 
    struct 
        module type S = 
        sig 
         type t 
         val get_fst : t -> X.el 
         val get_snd : t -> X.el 
         val make : X.el -> X.el -> t 
         val compare : t -> t -> int 
        end 
        end 
    

    有了,你可以写:

    module MakeOrderedPairSet (X : ORDERED_TYPE) : SET_TYPE(X).S = ... 
    
+0

为了比较......这是否意味着您可以在不使用包装模块的情况下在SML中编写参数化签名? –

+1

不,SML根本就没有这种能力(尽管一些SML方言可以让你写上类似的东西)。 –