代码之家  ›  专栏  ›  技术社区  ›  J Cooper

在F中使用“inline”#

  •  62
  • J Cooper  · 技术社区  · 14 年前

    这个 inline 在我看来,F#中的关键字与我在C中的用法有些不同。例如,它似乎影响函数的类型(什么是“静态解析类型参数”?不是所有的F类型都是静态解析的吗?)

    我应该什么时候用 内联 功能?

    4 回复  |  直到 14 年前
        1
  •  82
  •   kvb    14 年前

    这个 inline

    这适用的主要情况是运算符的使用。

    let add a b = a + b
    

    int -> int -> int ,但可能是 float -> float -> float 如果有代码在该类型上使用此函数)。但是,通过将此函数标记为inline,F#编译器将推断多态类型:

    let inline add a b = a + b
    // add has type ^a ->  ^b ->  ^c when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)
    

    类型参数 ^a ^b ,和 ^c 是“静态解析的类型参数”,这意味着参数的类型必须在使用这些参数的站点静态已知。这与常规类型参数(例如。 'a , 'b ,其中参数表示“稍后将提供的某种类型,但可以是任何类型”。

        2
  •  41
  •   Nick    3 年前

    当您需要定义一个函数时,应该使用inline,该函数必须在每次使用的位置对其类型进行求值(重新求值),而不是普通函数,普通函数只能在第一次使用的位置对其类型进行求值(推断),然后在此后的任何地方都被视为使用第一个推断类型签名进行静态类型化。

    在内联情况下,函数定义实际上是泛型/多态的,而在正常(非内联)情况下,函数是静态(通常是隐式)类型的。

    let inline add a b = a + b
    
    [<EntryPoint>]
    let main args = 
    
        let one = 1
        let two = 2
        let three = add one two
        // here add has been compiled to take 2 ints and return an int
    
        let dog = "dog"
        let cat = "cat"
        let dogcat = add dog cat
        // here add has been compiled to take 2 strings and return a string
    
        printfn "%i" three
        printfn "%s" dogcat   
    
        0
    

    将编译、生成和运行以生成以下输出:

    3  
    dogcat
    

    换言之,相同的add函数定义已用于生成两个整数相加的函数,以及连接两个字符串的函数(事实上,+上的基础运算符重载也是通过使用inline实现的)。

    然而,除了add函数不再内联声明外,此代码完全相同:

    let add a b = a + b
    
    [<EntryPoint>]
    let main args = 
    
        let one = 1
        let two = 2
        let three = add one two
        // here add has been compiled to take 2 ints and return an int
    
        let dog = "dog"
        let cat = "cat"
        let dogcat = add dog cat
        // since add was not declared inline, it cannot be recompiled
        // and so we now have a type mismatch here
    
        printfn "%i" three
        printfn "%s" dogcat   
    
        0
    

    将不编译,如果没有此投诉:

        let dogcat = add dog cat
                         ^^^ - This expression was expected to have type int
                               but instead has type string
    

    let inline flip f x y = f y x
    

    就像@pad对这个问题的回答一样 Different argument order for getting N-th element of Array, List or Seq

        3
  •  34
  •   J D    14 年前

    我应该什么时候用 inline 功能?

    内联 关键字在实践中是将高阶函数内联到调用站点,在调用站点中它们的函数参数也是内联的,以便生成一段单独完全优化的代码。

    内联 在下面 fold

      let inline fold f a (xs: _ []) =
         let mutable a = a
         for i=0 to xs.Length-1 do
            a <- f a xs.[i]
         a
    

    内联 内联 通过.NET元数据传输。

        4
  •  10
  •   Brian    14 年前

    这个 F# component design guidelines

    • 不要使用 inline
      • 例外:您可以考虑使用 在编写供其他F代码使用的数学库时,您希望编写针对不同数值数据类型的通用函数。

    对于“鸭式”类型的C++程序模板,有许多其他“有趣”的内联和静态成员约束。我的建议是像瘟疫一样避免所有这些。

    @kvb的答案更深入地解释了什么是“静态类型约束”。