如何使F#编译器将我的参数推断给泛型函数?

时间:2018-11-28 15:54:08

标签: generics f#

我写了一些测试代码来绕过泛型语法:

let add_stuff<'T> x y =
   printfn "%A" (x + y)

let stuff() = 
    add_stuff 5.5 2.4
    add_stuff 3 4

第二个add_stuff调用未编译。为什么是这样?为什么编译器不推断类型?

2 个答案:

答案 0 :(得分:4)

代码有2个问题:

首先,任何参数均未使用通用类型'T。需要像这样声明'T类型的参数:

// val add_stuff: 'T -> 'T -> unit
let add_stuff<'T> (x:'T) (y:'T) =
    printfn "%A" (x + y)

这将创建新的错误消息:

  

声明的类型参数'T'不能在这里使用,因为类型   参数在编译时无法解析

在这种情况下,问题是+运算符。它使用静态解析类型参数,这意味着您的函数也需要使用它们,这基本上意味着需要内联:

// val add_stuff: ^T -> ^T -> unit
let inline add_stuff (x:^T) (y:^T) =
    printfn "%A" (x + y)

请注意,类型签名'T中的差异是通用类型,可以在运行时解决。 ^T是一个SRTP,需要在编译时进行解析,因此需要使用inline关键字。

如果您未使用+运算符,则无需内联它。请注意pair_stuffadd_stuff之间的区别:

// val pair_stuff: 'T -> 'W -> unit
let pair_stuff (x:'T) (y:'W) =
    printfn "%A" (x , y)

// val add_stuff:  ^a -> ^b -> unit
let inline add_stuff x y =
    printfn "%A" (x + y)

let stuff() = 
    add_stuff 5.5 2.4
    add_stuff 3 4
    pair_stuff 5.5 2.4
    pair_stuff 3 4

stuff()
// 7.9
// 7
// (5.5, 2.4)
// (3, 4)

答案 1 :(得分:3)

您不能为此使用泛型,因为它们在运行时已解决并且不会因内联而有所不同。

您需要使用Statically Resolved Type Parameters,它将在编译时解决:

let inline add_stuff (x: ^X) (y: ^Y) =
    printfn "%A" (x + y)
  

静态解析的类型参数主要与成员约束一起使用,成员约束是允许您指定类型参数必须具有一个或多个特定成员才能使用的约束。无法使用常规的泛型类型参数来创建这种约束。