F#中没有显式函数参数的类型注释的值限制

时间:2018-03-02 11:03:47

标签: f#

我一直试图摆脱以下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>覆盖?有没有办法在没有明确指定参数的情况下声明这样的函数?

1 个答案:

答案 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的函数参数,编译器会从第一次使用中推断出它的类型。