使用显式指定的泛型参数推断通用约束

时间:2016-02-11 16:57:15

标签: generics f# type-inference

考虑以下代码:

let f<'a when 'a:comparison> (x: 'a) = ()
let g x = f x
let h<'b> (x: 'b) = f x

函数f具有通过比较约束的通用参数 在函数g中,我只使用f并让编译器推断它正确执行的泛型参数,从而得到g: 'a -> unit when 'a : comparison

但是,如果我需要显式指定泛型参数,如函数h,编译器由于某种原因无法推断约束,导致x下的红色波浪形,说“类型参数缺少约束'when'b:comparison'。

对于没有非泛型参数的函数,即let f<'a> = (),或其非泛型参数未提及泛型类型,即let f<'a> () = (),这尤其令人讨厌,因为我最终每次我在另一个通用函数中使用这些函数时必须指定约束:

let f<'a when 'a:comparison> () = ()
let g<'a> () = f<'a> () // Error: A type parameter is missing a constraint 
let h () = f<'a> () // h gets inferred as unit -> unit, losing generic parameter
let k<'a when 'a:comparison> () = f<'a> () // The only working way

让编译器为我推断约束是否有诀窍?

2 个答案:

答案 0 :(得分:2)

从第二组功能中删除gh生成警告:

  

这种结构导致代码的通用性低于   类型注释。类型变量'a已被约束为类型   'System.IComparable'。

因此,g中的错误似乎阻止了h的完整类型检查。

答案 1 :(得分:1)

只要您只在参数和/或返回类型之后注释类型参数,而不是函数名称,类型推断似乎有效。

从你的第一个例子开始:

let f<'a when 'a:comparison> (x: 'a) = ()

let i (x: 'b) = f x 
// val i : x:'b -> unit when 'b : comparison

如果参数本身具有泛型类型和/或其他类型约束,它也可以工作:

let j (x: 'c list) = f x.Head
// val j : x:'c list -> unit when 'c : comparison

let k (x: 'd when 'd:unmanaged) = f x
// val k : x:'d -> unit when 'd : unmanaged and 'd : comparison

你应该能够以这种方式编码,因为在函数名中指定type参数是不必要的。

即使您多次使用约束类型,您也只需要第一次描述它:

let l (x: 'e when 'e:unmanaged) (y : 'e) = f x
// val l : x:'e -> y:'e -> unit when 'e : unmanaged and 'e : comparison

所有相同的技巧都适用于返回类型:

let f'<'a when 'a:comparison> () = (new obj ()) :?> 'a

let g' () : 'b when 'b : unmanaged = f' ()
// val g' : unit -> 'b when 'b : unmanaged and 'b : comparison

因此,唯一的痛点是泛型函数既没有通用输入参数也没有泛型返回类型。