f#显式类型参数的用例是什么?



据我所知,值定义中的显式类型参数是克服"值限制"问题的一种方法。
还有其他情况下我需要使用它们吗?

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,返回一个string

let f (a:A<string>) = a.get().Length

最新更新