在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
但那也没有打字。
答案 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
表示签名S
和S'
的类声明相同。 #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