Tim*_*imC 13 f# inline quotations
有没有人知道为什么不sub
抛出异常add
?这是一个错误吗?
open Microsoft.FSharp.Linq.QuotationEvaluation
let inline add x = x + x
let inline sub x = x - x
let answer = <@ add 1 @>.Eval() // 2, as expected
let answer2 = <@ sub 1 @>.Eval() // NotSupportedException
Run Code Online (Sandbox Code Playgroud)
注意,如果没有inline关键字,则不会抛出异常(但代码不是通用的)此外,仅在使用引用时抛出异常.正常评估工作正常.
谢谢
编辑:简化代码示例
Tom*_*cek 13
感谢您提出这个问题 - 这是一个非常好的错误报告,只有一个简单的复制品,我无法相信这一点,但您完全正确.加上工作,但减去不工作.
问题是,sub
并add
编译为泛型方法,LINQ版本调用这些泛型方法.内联是在存储引号后执行的,因此引用的代码包含对sub
方法的调用.这在普通F#代码中不是问题,因为函数是内联的,并且运算符在某些数字类型上被解析为+或 - .
但是,通用版本使用动态查找.如果你研究一下prim-types.fs:3530
,你会看到:
let inline (+) (x: ^T) (y: ^U) : ^V =
AdditionDynamic<(^T),(^U),(^V)> x y
when ^T : int32 and ^U : int32 = (# "add" x y : int32 #)
when ^T : float and ^U : float = (# "add" x y : float #)
// ... lots of other cases
Run Code Online (Sandbox Code Playgroud)
这AdditionDynamic
是从泛型方法调用的内容.它执行动态查找,速度较慢,但它会起作用.有趣的是,对于减号运算符,F#库不包含动态实现:
[<NoDynamicInvocation>]
let inline (-) (x: ^T) (y: ^U) : ^V =
((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y))
when ^T : int32 and ^U : int32 = (# "sub" x y : int32 #)
when ^T : float and ^U : float = (# "sub" x y : float #)
// ... lots of other cases
Run Code Online (Sandbox Code Playgroud)
我不知道为什么会这样 - 我认为没有任何技术原因,但它解释了为什么你得到你报告的行为.如果您使用ILSpy查看已编译的代码,您将看到该add
方法执行某些操作并且该sub
方法只是抛出(因此这是异常的来源).
至于解决方法,您需要以不使用泛型减运算符的方式编写代码.可能最好的选择是避免inline
函数(通过使用sub_int
或sub_float
)或编写自己的动态实现sub
(可以使用DLR非常有效地完成(参见本文).
归档时间: |
|
查看次数: |
378 次 |
最近记录: |