gpt4 book ai didi

oop - 为什么使用类类型时,OCAML 对象中未绑定(bind)的类型变量不出现?

转载 作者:行者123 更新时间:2023-12-04 11:11:57 26 4
gpt4 key购买 nike

我想了解 OCAML 对象这种行为的原因。假设我有一个类(class) A调用另一个类的对象的方法B .从原理上讲,A#f 调用 B#g 和 B#h。 OOP 中的常规做法是我想避免将 B 用作固定的具体类,而是只为 B 声明一个接口(interface)。在 OCAML 中执行此操作的最佳方法是什么?我尝试了几种选择,但我不太明白为什么其中一些有效而另一些无效。以下是代码示例。

版本 1:

 # class classA = object
method f b = b#g + b#h
end ;;
Error: Some type variables are unbound in this type:
class a : object method f : < g : int; h : int; .. > -> int end
The method f has type (< g : int; h : int; .. > as 'a) -> int where 'a
is unbound

这种行为是众所周知的:OCAML 正确推断出 b具有开放对象类型 <g:int;h:int;..>但随后提示我的类没有声明任何类型变量。所以看来 classA需要有类型变量;然后我明确地介绍了一个类型变量。

版本 2:
 # class ['a] classA2 = object
method f (b:'a) = b#g + b#h
end ;;
class ['a] classA2 :
object constraint 'a = < g : int; h : int; .. > method f : 'a -> int end

这可行,但该类现在是具有类型约束的显式多态性,如 OCAML 所示。类类型包含类型变量 'a 也令人困惑。 ,但我仍然可以说 let x = new classA2未指定 'a 的类型值.为什么会这样?
classA2 的另一个缺点是一个显式类型约束 (b:'a)包含一个类型变量。毕竟我知道 b必须符合固定接口(interface)而不是未知类型 'a .我希望 OCAML 验证这个接口(interface)确实是正确的。

所以在版本 3 中,我首先声明了一个接口(interface) classB作为类类型,然后声明 b必须是这种类型:
 # class type classB = object method g:int method h:int end;;
class type classB = object method g : int method h : int end
# class classA3 = object method f (b:classB) = b#g + b#h end;;
class classA3 : object method f : classB -> int end

这也有效,但我的困惑仍然存在:为什么不 classA3需要显式多态了吗?

问题总结:
  • 为什么可以使用new classA2未指定 'a 的类型即使 classA2用类型变量声明 'a ?
  • 为什么classA3接受类型约束 (b:classB)并且不再需要绑定(bind)类型变量?
  • classA2 的功能吗?和 classA3以某种微妙的方式有所不同,如果是,如何?
  • 最佳答案

    这会有点复杂,所以请坚持。首先,让我添加一个 classA4变体,这恰好是您真正需要的。

    class classA4 = object
    method f : 'a. (#classB as 'a) -> int = fun b -> b#g + b#h
    end

    类(class) classA2 , classA3classA4都是有细微差别的,区别在于OCaml如何对待类型多态和对象多态。假设有两个类 b1b2 , 执行 classB类型。

    就对象多态而言,这意味着 b1 类型的表达式可以强制输入 classB使用强制语法 (new b1 :> classB) .这种类型强制会丢弃类型信息(您不再知道对象的类型为 b1),因此必须明确说明。

    就类型多态而言,这意味着类型 b1可用于替代任何具有约束 #classB 的类型变量(或 < g : int ; h : int ; .. > )。这不会丢弃任何类型信息(因为类型变量被实际类型替换),因此它由类型推断算法执行。

    方法 fclassA3需要 classB 类型的参数,这意味着强制类型转换:
    let b = new b1 
    let a = new classA3
    a # f b (* Type error, expected classB, found b1 *)
    a # f (b :> classB) (* Ok ! *)

    这也意味着(只要你强制),任何实现 classB 的类可以使用。

    方法 fclassA2期望与约束 #classB 匹配的类型的参数,但是 OCaml 要求这样的类型不应该是未绑定(bind)的,所以它是在类级别绑定(bind)的。这意味着 classA2 的每个实例将接受 的参数单实现 classB 的任意类型(并且该类型将被类型推断)。
    let b1 = new b1 and b2 = new b2
    let a = new classA2
    a # f b1 (* 'a' is type-inferred to be 'b1 classA2' *)
    a # f b2 (* Type error, because b1 != b2 *)

    需要注意的是 classA3相当于 classB classA2 ,这就是为什么它不需要绑定(bind)类型变量的原因,也是为什么它的表达力严格低于 classA2 .

    方法 fclassA4已使用 'a. 给出显式类型语法,它在方法级别而不是类级别绑定(bind)类型变量。它实际上是一个通用量词,这意味着 « 可以为任何类型调用此方法 'a实现 #classB » :
    let b1 = new b1 and b2 = new b2
    let a = new classA4
    a # f b1 (* 'a is chosen to be b1 for this call *)
    a # f b2 (* 'a is chosen to be b2 for this call *)

    关于oop - 为什么使用类类型时,OCAML 对象中未绑定(bind)的类型变量不出现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11177125/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com