是否可以使用呼叫者的信息进行类型推理



例如Haskell或ML中的功能F1和F2。假设F2调用F1。确实要键入推理只使用F1可以调用的信息,这仅仅是查看F1的定义。或者它还可以查看F2在F1上输入推理时如何调用F1。例如,F2调用F1时可能会传递文字,这将限制F1的参数类型。

取决于函数 f1是由声明还是其他方式约束的(例如,作为 f2的函数参数)。在前一种情况下,它的类型可以推广为多态性,在后者中不能概括,未解决的部分取决于上下文。即使在前一种情况下,也可能适用其他规则,例如ML的价值限制。

在Haskell中考虑此示例:

f1 = x -> x  -- polymorphic: f1 :: a -> a
f2 = f1 True  -- instantiates f1 :: Bool -> Bool
f2 = let f1 = x -> x in f1 True  -- likewise
f2 = (f1 -> f1 True) (x -> x)  -- here, f1 cannot be polymorphic,
                                 -- so the lambda is restricted to Bool -> Bool by the call

,同样在SML中:

val f1 = fn x => x  (* polymorphic, f1 : 'a -> 'a *)
val f2 = f1 true
val f2 = let val f1 = fn x => x in f1 true end  (* likewise *)
val f2 = (fn f1 => f1 true) (fn x => x)  (* f1 monomorphic, f1 : bool -> bool *)
val f1 = let _ = 0 in fn x => x end  (* value restriction applies, f1 cannot be polymorphic *)
val f2 = f1 true  (* determines type f1 : bool -> bool *)

为了清楚起见,我在这里不使用缩写函数声明语法。

类型系统不会使用有关呼叫者的信息来确定函数可以处理的类型 - 这既是过于限制的,又无法实现。例如,假设(Haskell)

aList :: [Int]
aList = [1,2,3]
one = head aList

随后将限制head的类型从[a] -> a[Int] -> Int;之后,head ["hello", "world"]将是不可能的,下次我们要在其他类型上使用它时,我们必须重新定义head。但是,在one的定义的上下文中,head实际上具有[Int] -> Int类型作为其类型中的变量进行实例化。但这不会改变head或其类型的全局定义。

(实际上,编译器可以专门为仅在几种情况下调用它的功能,并将代码调整为所传递的特定类型,只要它不更改程序语义。)

最新更新