代码之家  ›  专栏  ›  技术社区  ›  filiard

OCaml中模块中的抽象类型

  •  2
  • filiard  · 技术社区  · 7 年前

    我在OCaml中有非常简单的签名和模块:

    module type S = sig
      type t 
      val y : t
    end;;
    

    module M2 : S = struct
      type t = int
      let x = 1
      let y = x+2
    end;;
    

    我不能像这样使用构造

    M2.y
    

    得到 3 除非我指定模块为

    module M2 : S with type t = int = struct ...
    

    为什么会这样?已经有声明说 type t = int

    1 回复  |  直到 7 年前
        1
  •  5
  •   ErikMD    4 年前

    混凝土, int 的值 M2.y 确实不可用,因为满足以下两个条件:

    1. 的类型 y 摘要 在签名中 S
      (没有 type t = ... 此处)

    2. 模块 M2 是制造的 不透明的 关于签名 S
      (换句话说,仅限于签名 S 通过 符号 : S )

    因此,您确实获得:

    let test = M2.y ;;
    (* val test : M2.t = <abstr> *)
    

    根据关键字建议 <abstr> ,这与 抽象类型 . 这个概念是由OCaml的类型规则强制实现的一个非常强大的特性,它可以防止模块的任何用户拥有签名 S 检查这种抽象类型的具体内容。因此,此属性对于实现所谓的 abstract data types (ADT) 在OCaml中,通过仔细分离ADT的实现和签名。

    如果缺少上述两个条件中的任何一个,则类型将不再是抽象的,并且 y 将出现。

    更准确地说:

    1. 如果类型 t 混凝土制成,您可以获得:

       module type S = sig
         type t = int
         val y : t
       end
      
       module M2 : S = struct
         type t = int
         let x = 1
         let y = x+2
       end
      
       let test = M2.y ;;
       (* val test : M2.t = 3 *)
      

      但在实践中,这不是很有趣,因为你失去了一般性。然而,更有趣的方法是在签名中添加“evaluator”或“pretty printer”函数,例如值 int_of_t 以下内容:

       module type S = sig
         type t
         val y : t
         val int_of_t : t -> int
       end
      
       module M2 : S = struct
         type t = int
         let x = 1
         let y = x+2
         let int_of_t x = x
       end
      
       let test = M2.(int_of_t y) ;;
       (* val test : int = 3 *)
      
    2. 否则,如果模块 平方米 是透明的,您可以获得:

       module type S = sig
         type t
         val y : t
       end
      
       module M2 (* :S *) = struct
         type t = int
         let x = 1
         let y = x+2
       end
      
       let test = M2.y ;;
       (* val test : int = 3 *)
      

    最后,值得注意的是,除了抽象类型的特性之外,OCaml还提供了 私有类型 这可以看作是模块化开发中使用的具体类型和抽象类型之间的权衡。有关此概念的更多详细信息,请参见示例 Chap. 8 of Caml ref man .