我希望我没有错过任何明显的东西,但我一直在玩F#表达式,我想动态评估引用的表达式.例如,我想写这样的东西:
let x = <@ 2 * 5 @> let y = transform x // replaces op_Multiply with op_Addition, or <@ 2 + 5 @> let z = eval y // dynamically evaluates y, returns 7
是否有内置的F#方法可以评估引用的表达式,还是我必须自己编写?
我已经实现了一个基于反射的Quotation评估器作为Unquote的一部分(这是2.0.0版本的新功能).
> #r @"..\packages\Unquote.2.2.2\lib\net40\Unquote.dll" --> Referenced '..\packages\Unquote.2.2.2\lib\net40\Unquote.dll' > Swensen.Unquote.Operators.eval <@ sprintf "%A" (1,2) @>;; val it : string = "(1, 2)"
我测得它比PowerPack评估员快50倍.当然,这将因情况而异.但Unquote在解释表达式时通常比PowerPack更快.
它还支持比PowerPack的求值程序更多的表达式,包括VarSet,PropertySet,FieldSet,WhileLoop,ForIntegerRangeLoop和Quote.实际上,Unquote的求值程序支持除 NewDelegate,AddressSet和AddressOf 之外的所有引用表达式,我计划最终支持所有这些表达式.
不,没有内置的方法来编译F#引用.使用PowerPack LINQ,您可以将一些引用转换为.NET System.Linq.Expressions.Expression,并使用它来编译它们.
引用是为了允许其他代码解释,例如定位SQL或GPU卡.
但是,在hubfs上的帖子中,有人暗示这是一个常见的请求,我们会看一下.
您可以使用DLL Eval
提供的扩展成员评估F#引用FSharp.PowerPack.Linq
,如下所示:
#r "FSharp.PowerPack.Linq.dll" open Linq.QuotationEvaluation let f = <@2 + 3@> f.Eval()
请注意,必须open
使用Linq.QuotationEvaluation
命名空间才能使此扩展成员可用.
还有一个Compile
扩展成员返回暂停,但它似乎不会提高性能.
2016年更新
的Evaluate
扩展方法,现在可以在NuGet包中找到FSharp.Quotations.Evaluator
#r "../packages/FSharp.Quotations.Evaluator.1.0.7/lib/net40/FSharp.Quotations.Evaluator.dll" open FSharp.Quotations.Evaluator let f = <@ 2 + 3 @> f.Evaluate()