据我所知,值定义中的显式类型参数是克服“值限制”问题的一种方法。
当我需要使用它们时,还有其他情况吗?
Upd:我的意思是“显式通用构造”,其中类型参数括在尖括号中,即
let f<'T> x = x
据我所知,值定义中的显式类型参数是克服“值限制”问题的一种方法。
当我需要使用它们时,还有其他情况吗?
Upd:我的意思是“显式通用构造”,其中类型参数括在尖括号中,即
let f<'T> x = x
多态递归是另一种情况。也就是说,如果你想在函数体中使用不同的泛型实例化,那么你需要在定义上使用显式参数:
// perfectly balanced tree
type 'a PerfectTree =
| Single of 'a
| Node of ('a*'a) PerfectTree
// need type parameters here
let rec fold<'a,'b> (f:'a -> 'b) (g:'b->'b->'b) : 'a PerfectTree -> 'b = function
| Single a -> f a
| Node t -> t |> fold (fun (a,b) -> g (f a) (f b)) g
let sum = fold id (+)
let ten = sum (Node(Node(Single((1,2),(3,4)))))
这可能很少见,但是当您想防止进一步泛化时(第 14.6.7 节):
值和成员定义上的显式类型参数定义会影响类型推断和泛化的过程。特别是,包含显式泛型参数的声明不会被泛化到那些泛型参数之外。例如,考虑这个函数:
let f<'T> (x : 'T) y = x
在类型推断期间,这将导致以下类型的函数,其中 '_b 是尚未解析的类型推断变量。
f<'T> : 'T -> '_b -> '_b
为了允许对这些定义进行泛化,要么删除显式泛型参数(如果可以推断出它们),要么使用所需数量的参数,如以下示例所示:
let throw<'T,'U> (x:'T) (y:'U) = x
当然,您也可以使用类型注释来完成此操作。
最明显的例子:编写一个函数来计算字符串的长度。
你必须写:
let f (a:string) = a.Length
你需要注释。没有注释,编译器无法确定a
. 存在其他类似的示例 - 特别是在使用设计为从 C# 使用的库时。
处理更新的答案:
同样的问题适用 -string
变成A<string>
了具有get
返回 a的方法string
let f (a:A<string>) = a.get().Length