inline在我看来,F#中的关键字与我在例如C中使用的目的有些不同.例如,它似乎影响函数的类型(什么是"静态解析的类型参数"?不是所有的F#类型静态解决?)
我inline什么时候应该使用功能?
kvb*_*kvb 78
的inline关键字表示一个函数定义应该内联插入其使用的任何代码.大多数情况下,这不会对函数的类型产生任何影响.但是,在极少数情况下,它可以导致具有更通用类型的函数,因为存在不能在.NET中的代码的编译形式中表达的约束,但是可以在内联函数时强制执行.
这适用的主要情况是使用运营商.
let add a b = a + b
Run Code Online (Sandbox Code Playgroud)
将有一个单态推断类型(可能int -> int -> int,但它可能是类似的,float -> float -> float如果您有代码,在该类型使用此函数).但是,通过内联标记此函数,F#编译器将推断出多态类型:
let inline add a b = a + b
// add has type ^a -> ^b -> ^c when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
Run Code Online (Sandbox Code Playgroud)
在.NET上的编译代码中,无法以第一类方式编码此类型约束.但是,F#编译器可以在其内联函数的站点强制执行此约束,以便在编译时解析所有运算符使用.
类型参数^a,^b和^c是"静态解析的类型参数",这意味着必须在使用这些参数的站点静态地知道参数的类型.这与普通类型参数(例如'a,'b等等)形成对比,其中参数意味着类似"稍后将提供但可以是任何东西的某种类型".
Jon*_*rop 31
我
inline什么时候应该使用功能?
inline关键字在实践中最有价值的应用是将高阶函数内联到调用站点,其中函数参数也被内联,以便生成单独完全优化的代码片段.
例如,inline以下fold函数使其快5倍:
let inline fold f a (xs: _ []) =
let mutable a = a
for i=0 to xs.Length-1 do
a <- f a xs.[i]
a
Run Code Online (Sandbox Code Playgroud)
请注意,这与inline大多数其他语言几乎没有什么相似之处.您可以使用C++中的模板元编程实现类似的效果,但F#也可以在编译的程序集之间内联,因为它inline是通过.NET元数据传达的.
dav*_*zen 29
当您需要定义一个必须在每次使用的站点上评估其类型(re)的函数时,您应该使用内联,而不是普通函数,该函数将仅在首次使用的站点评估(推断)其类型,然后被视为静态输入其后的其他地方的第一推断类型签名.
在内联案例中,函数定义实际上是通用/多态的,而在正常(非内联)情况下,函数是静态的(通常是隐式)类型.
因此,如果您使用内联,请使用以下代码:
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
Run Code Online (Sandbox Code Playgroud)
将构建并编译以生成以下输出:
3
dogcat
Run Code Online (Sandbox Code Playgroud)
换句话说,使用相同的add函数定义来生成一个添加到整数的函数,以及一个连接两个字符串的函数(事实上,基于+的底层运算符重载也是使用内联在引擎盖下实现的).
除了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
Run Code Online (Sandbox Code Playgroud)
不会编译,因此投诉失败:
let dogcat = add dog cat
^^^ - This expression was expected to have type int
but instead has type string
Run Code Online (Sandbox Code Playgroud)
使用内联的合适位置的一个很好的例子是,当你想要定义一个泛型函数来反转带有2个参数的函数的参数的应用顺序时,例如
let inline flip f x y = f y x
Run Code Online (Sandbox Code Playgroud)
正如@pad对这个问题的答案所做的那样 获取Array,List或Seq的第N个元素的不同参数顺序.
| 归档时间: |
|
| 查看次数: |
7509 次 |
| 最近记录: |