代码之家  ›  专栏  ›  技术社区  ›  Cthutu

如何让F编译器将参数推断为泛型函数?

  •  2
  • Cthutu  · 技术社区  · 6 年前

    我编写了一些测试代码来概括泛型的语法:

    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 回复  |  直到 6 年前
        1
  •  4
  •   AMieres    6 年前

    代码有两个问题:

    首先,泛型类型 '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_stuff add_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)
    
        2
  •  3
  •   Chad Gilbert    6 年前

    不能对此使用泛型,因为它们是在运行时解析的,并且不会因内联而变化。

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

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

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