【问题标题】:Class instance type coercion in module signature模块签名中的类实例类型强制
【发布时间】:2011-01-10 12:58:17
【问题描述】:

我的几个模块包含全局类实例,这些实例通过private_methodpublic_method 这两种方法实现给定的类类型。

我希望MyModule.my_instance # public_method 可以在我的程序中的任何位置使用,而MyModule.my_instance # private_method 只能在MyModule 中使用。

我尝试了以下方法:

class type public_type = object
  method public_method  : int
end ;;

class type private_type = object
  method public_method  : int
  method private_method : int
end ;;

let make_private : unit -> private_type = fun () -> object
  method public_method  = 0
  method private_method = 0
end ;;

module type MY_MODULE = sig
  val my_instance : public_type
end

module MyModule : MY_MODULE = struct
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)
end 

但是,这会导致错误:

值不匹配:

val my_instance : private_type

不包含在

val my_instance : public_type

可以手动写强制:

module MyModule : MY_MODULE = struct
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)

  let my_instance = (my_instance :> public_type)
end 

但我宁愿不要将这样简单的代码大小加倍。

您对为什么会发生这种情况以及我如何解决它有什么建议吗?

【问题讨论】:

    标签: module ocaml signature coercion


    【解决方案1】:

    ocaml 中没有隐式强制。也许值得将强制转换为仿函数(如果您有多个具有这些相同属性的模块):

    module Hide(M:sig val my_instance : private_type end) : MY_MODULE =
    struct
      let my_instance = (M.my_instance :> public_type)
    end
    
    module MyModule = Hide (struct
      let my_instance = make_private ()
      let _           = print_int (my_instance # private_method)
    end)
    

    【讨论】:

    • 我有点希望将 MyModule 显式强制转换为 MY_MODULE 将作为对...内所有值的显式强制...
    • manual (6.11.1) 说The expression ( module-expr : module-type ) checks that the type of module-expr is a subtype of module-type 但它没有说任何关于强制的内容,所以我想这是一种预期的行为。 IIRC 在 3.12 中可以使用 :> 强制模块
    • 恐怕 3.12 没有做任何事情,至少不像更新日志中提到的那样 :-( 我知道这是不可能的,我必须解决它。但是 为什么没有实现?如果他们这样做了,类型系统是否存在实际问题,或者他们只是没有考虑过?
    • 嗯,也许它被提到为即将推出的功能,现在不记得了。最好在邮件列表上问这个。我的猜测是 ocaml 风格很适合明确地做事。
    【解决方案2】:

    可能解决此问题的最佳技术是使用 Garrigue 所描述的private row types(“私人行类型:抽象未命名”;请查看它,因为我无法发布第二个链接)。这可以与显式对象类型表达式一起使用:

    module type MY_MODULE2 = sig
      type t = private < public_method : int; ..>
      val my_instance : t
    end ;;
    
    module MyModule2 : MY_MODULE2 = struct
      type t = private_type
      let my_instance = make_private ()
      let _           = print_int (my_instance # private_method)
    end  ;;
    

    或使用对象路径(这是您需要的):

    module type MY_MODULE3 = sig
      type t = private #public_type
      val my_instance : t
    end ;;
    
    module MyModule3 : MY_MODULE3 = struct
      type t = private_type
      let my_instance = make_private ()
      let _           = print_int (my_instance # private_method)
    end  ;;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-29
      • 1970-01-01
      • 2017-11-17
      相关资源
      最近更新 更多