OCaml对象的多态性输入问题

时间:2016-06-19 18:31:09

标签: object polymorphism ocaml typing

在4.03.0。

我有这个代码,基本上是:

module rec First : sig

  type field
  type 'a target = <at_least_this_method: field; .. > as 'a

end = First
and Second : sig

  class foo : object
    method at_least_this_method : First.field
  end

end = Second
and Third : sig

  class usage :
    object

      method action : #Second.foo First.target -> unit

    end

end = struct

  class usage = object
    method action (a : #Second.foo First.target) = ()
  end

end

method action的最后一行无法输入错误消息:

Error: Some type variables are unbound in this type:
         class usage :
           object method action : #Second.foo First.target -> unit end
       The method action has type (#Second.foo as 'a) First.target -> unit
       where 'a is unbound

我也尝试过这样的事情:

  class usage = object
    method action = fun (type t) (b : (#Second.foo as t) First.target) -> ()
  end

但那也没有打字。

3 个答案:

答案 0 :(得分:5)

我想您要编写以下代码:

module rec First : sig
  type field
  class type target = object method at_least_this_method: field end
end = First
and Third : sig
  class usage :
    object
      method action : #First.target -> unit
    end
end = struct
  class usage = object
    method action : 'a. (#First.target as 'a) -> unit = fun a -> ()
  end
end

我不确定你为什么在这里使用递归模块。 他们不适合上课。特别是,接口不会传播到模块内的类。这就是为什么你需要在action的主体中明确写出多态方法Third的类型。

答案 1 :(得分:2)

让我添加一个不成功的试验来解决问题。

#c是一个开放类型,它包含一个隐式表达..部分对象类型的类型变量,因为这个隐藏的类型变量没有被量化,所以会出现类型错误。

有趣且令人困惑的是,即使隐藏变量没有明确量化,签名也不会拒绝使用#A.foo。以下类型检查。 (由于对递归模块输入的恐惧,我使用仿函数改变了你的例子):

module Make(A : sig
  type field
  type 'a target = <at_least_this_method: field; .. > as 'a

  class foo : object
    method at_least_this_method : field
  end
end) = struct
  module type S = sig
    class usage : object
        method action : #A.foo A.target -> unit
    end
  end
  module type S' = sig
    class usage : object
        method action : 'a . (#A.foo as 'a) A.target -> unit
    end
  end

ocamlc -c -i表示签名SS'的类声明相同。 #A.foo中的类型变量在方法级别进行量化,并使action成为多态方法。

@ objmagic的答案是将这种多态性转移到类级别。那么如果我们想让方法保持多态,我们该怎么做?:

class usage = object
  method action : 'a . (#A.foo as 'a) A.target -> unit = assert false
end

但这不是类型检查:

Error: This expression has type 'a. (#A.foo as 'a) A.target -> unit
       but an expression was expected of type
         'b. (#A.foo as 'b) A.target -> unit
       The type variable 'c occurs inside 'c

类型错误完全是神秘的。对我而言,它是穿越物体打字危险线的标志。每当我看到这种错误消息时,我天真地认为根本不可能定义这种类型的方法,或者它是对象输入和撤退的错误......

顺便说一句,定义具有该类型的多态记录没有问题:

type t = { action : 'a . (#A.foo as 'a) A.target -> unit }
let t = { action = fun _ -> assert false }

答案 2 :(得分:1)

编辑:请参阅下面的@ gariguejej的答案以获得更好的解释。

我不是物体类型系统的专家,但这是我的两分钱。

将您的代码更改为:

module rec First : sig

  type field
  type 'a target = <at_least_this_method: field; .. > as 'a

end = First
and Second : sig

  class foo : object
    method at_least_this_method : First.field
  end

end = Second

and Third : sig

  class ['a] usage :
    object
      method action : 'a First.target -> unit
    end

end = struct

  class ['a] usage = object
    method action : 'a First.target -> unit = fun a -> ()
  end

end

使用ocaml -i,我们可以看到'a被限制为constraint 'a = < at_least_this_method : First.field; .. >

module rec First :
  sig
    type field
    type 'a target = 'a constraint 'a = < at_least_this_method : field; .. >
  end
and Second :
  sig class foo : object method at_least_this_method : First.field end end
and Third :
  sig
    class ['a] usage :
      object
        constraint 'a = < at_least_this_method : First.field; .. >
        method action : 'a First.target -> unit
      end
  end

当然,如果您希望它是一个封闭的对象类型,您也可以手动约束'a<at_least_this_method: field>。例如,

module rec First : sig

  type field
  type 'a target = <at_least_this_method: field; .. > as 'a

end = First
and Second : sig

  class foo : object
    method at_least_this_method : First.field
  end

end = Second

and Third : sig

  class ['a] usage :
    object
      constraint 'a = <at_least_this_method:First.field>
      method action : 'a First.target -> unit
    end

end = struct

  class ['a] usage = object
    constraint 'a = <at_least_this_method:First.field>
    method action : 'a First.target -> unit = fun a -> ()
  end

end

请参阅手册Chapter 3.10