我一直试图摆脱以下F#函数中的显式参数:
let mapToSelf (s: seq<'a>): seq<'a> = s |> Seq.map id
这个带有显式参数s
的版本按预期推断了类型seq<'a> -> seq<'a>
,我可以用它来映射不同类型的序列:
let stringSeq = mapToSelf [ "asd"; "qwe" ]
let intSeq = mapToSelf [ 1; 2; 3 ]
到目前为止,这么好。现在我想删除显式函数参数s
,如下所示,我(错误地?)期望等同于第一个版本:
let mapToSelf: (seq<'a> -> seq<'a>) = Seq.map id
现在我在这一行收到警告:
let stringSeq = mapToSelf [ "asd"; "qwe" ]
// The construct causes code to be less generic than indicated by the type annotations
并且下一行有错误,因为该函数现在具有签名(seq<string> -> seq<string>)
:
let intSeq = mapToSelf [ 1; 2; 3 ]
// The expression was expected to have type 'string', but here was type 'int'
我的问题是:为什么我自己指定的通用类型签名seq<'a> -> seq<'a>
会被不太通用的seq<string> -> seq<string>
覆盖?有没有办法在没有明确指定参数的情况下声明这样的函数?
答案 0 :(得分:3)
您只需要使用泛型类型装饰绑定:
> let mapToSelf<'T> : seq<'T> -> seq<'T> = Seq.map id;;
val mapToSelf<'T> : (seq<'T> -> seq<'T>)
> mapToSelf [| 1; 2 |];;
val it : seq<int> = seq [1; 2]
> mapToSelf [ "1"; "2" ];;
val it : seq<string> = seq ["1"; "2"]
为什么我自己指定的通用类型签名
seq<'a> -> seq<'a>
会被不太通用的seq<string> -> seq<string>
覆盖?
如果没有类型为generalize的函数参数,编译器会从第一次使用中推断出它的类型。