Function Subtyping.

函数 (方法) 也拥有它的类型,因此研究函数类型间的 subtyping 关系也是很有必要的。It is just as important for understanding how to safely override methods in object-oriented languages.

When we talk about function subtyping, we are talking about using a function of one type in place of a function of another type.

我们以 higher-order function 为例研究函数类型间的 subtyping 关系:distMoved function computes the distance between the two-dimensional point p and the result of calling f with p.

1
2
3
4
5
6
7
8
9
fun distMoved (f : {x:real,y:real}->{x:real,y:real},
p : {x:real,y:real}) =
let val p2 : {x:real,y:real} = f p
val dx : real = p2.x - p.x
val dy : real = p2.y - p.y
in Math.sqrt(dx*dx + dy*dy) end

fun flip p = {x=~p.x, y=~p.y}
val d = distMoved(flip, {x=3.0, y=4.0})

那么函数 distMoved 的类型为 (({x:real,y:real}->{x:real,y:real}) * {x:real,y:real}) -> real.

函数 flip 的类型为 {x:real, y:real} -> {x:real, y:real},与函数 distMoved 期待的参数类型是相符的;以函数 flip 为参数调用函数 distMoved 没有用到 subtyping。

Convariant Return Type

The subtyping for the return types works covariant as for the types overall.

函数类型与其返回值类型的 subtyping 关系是 covariant (协变) 的: If ta <: tb, then t -> ta <: t -> tb.

1
2
fun flipGreen p = {x=~p.x, y=~p.y, color="green"}
val d = distMoved(flipGreen, {x=3.0, y=4.0})

如上例,flipGreen 函数作为参数传入 distMoved 函数不会产生任何问题。

  • flipGreen 函数的返回值类型为 {x:real,y:real,color:string},是 distMoved 形参函数返回值类型 {x:real,y:real} 的 subtype。
  • flipGreen 函数类型 {x:real,y:real}->{x:real,y:real,color:string}distMoved 形参函数类型 {x:real,y:real}->{x:real,y:real} 的 subtype。

可以看出函数类型与其返回值类型 subtyping 的协变关系。

Contravariant Argument Type

The subtyping for argument types is the reverse of the subtyping for the types overall.

函数类型与其参数类型的 subtyping 关系是 contravariant (逆变) 的: If ta <: tb, then tb -> t <: ta -> t.

1
2
fun flipX_Y0 p = {x=~p.x, y=0}
val d = distMoved(flipX_Y0, {x=3.0, y=4.0})

如上例,flipX_Y0 函数作为参数传入 distMoved 函数不会产生任何问题。

  • flipX_Y0 函数的参数类型为 {x:real},是 distMoved 形参函数参数类型 {x:real,y:real} 的 supertype。
  • flipX_Y0 函数类型 {x:real}->{x:real,y:real}distMoved 形参函数类型 {x:real,y:real}->{x:real,y:real} 的 subtype。

可以看出函数类型与其参数类型 subtype 的逆变关系。

The general rule for function subtyping is: If t3 <: t1 (argument type) and t2 <: t4 (return type), then t1->t2 <: t3->t4. This rule, combined with reflexivity lets us use contravariant arguments, covariant results, or both.

注意在 OOP 语言中,self (或 this) 是被特殊处理的,它的类型与对象的类型始终是 convariant (共变) 的。