文 / 李博(光宇广贞)
《方法多态与Duck typing、C#之拙劣与F#之优雅》文末留了个尾巴,F# 的 inline 与 ^ 算符如何联袂完成方法多类的类型检查的。本文讨论这一问题。
《F# 手册》§5.1.2 提到:
A type of the form ^ident is a statically resolved variable type. A fresh type inference variable is created and added to the type inference environment (see §14.6). This type variable is tagged with an attribute indicating it may not be generalized except at inline definitions (see §14.7), and likewise any type variable with which it is equated via a type inference equation may similarly not be generalized.
问题解决了。那范型 'a 与 ^a 的区别呢?差就差在 ^a 需要 inline,见如下示例:
> let id (a : 'a) = a;;
val id : 'a -> 'a
> id 1, id "hi";;
val it : int * string = (1, "hi") // Good, it's generic
> let id (a : ^a) = a;;
let id (a : ^a) = a;;
-------------^^
stdin(8,14): warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'obj'.
val id : obj -> obj
> id 1, id "hi";;
val it : obj * obj = (1, "hi") // Constrained to obj - not generic
> let inline id (a : ^a) = a;;
val inline id : ^a -> ^a
> id 1, id "hi";;
val it : int * string = (1, "hi") // Since it's inline, it's generic