在F#中评估引用表达式

13

希望我没有错过什么显而易见的东西,但我一直在尝试使用 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#方法可以评估引用表达式,还是我必须编写自己的方法?

5个回答

18

作为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)"

我已经测量过,Unquote解释器比PowerPack的解释器快了多达50倍。当然,这会因情况而异。但是,在解释表达式方面,Unquote通常比PowerPack快得多。
此外,它支持比PowerPack的解释器更多的表达式,包括VarSet、PropertySet、FieldSet、WhileLoop、ForIntegerRangeLoop和Quote。事实上,Unquote的解释器支持所有引用表达式,除了NewDelegate、AddressSet和AddressOf,我计划最终支持它们。

有没有一种方法可以使用您的库进行任意取消引用,而不需要测试部分? - Chad Zawistowski
2
@ChadZawistowski 是的,有一些通用函数可用于任意反引号(引号解构和求值),包括 decompilereducereduceAllevalunquote - Stephen Swensen

9

没有内置的方法来编译F#引用。使用PowerPack LINQ,您可以将某些引用转换为.NET System.Linq.Expressions.Expression,并使用它们进行编译。

引用是为了允许对代码进行其他解释,例如针对SQL或GPU卡。

但是,在hubfs上的帖子中,暗示这是一个常见的请求,并且将会加以考虑。


8
您可以使用 FSharp.PowerPack.Linq DLL 提供的 Eval 扩展成员来评估 F# 引用,具体操作如下:
#r "FSharp.PowerPack.Linq.dll"

open Linq.QuotationEvaluation
let f = <@2 + 3@>
f.Eval()

注意,您必须打开 Linq.QuotationEvaluation 命名空间才能使用此扩展成员。
还有一个 Compile 扩展成员返回悬挂,但似乎并不会提高性能。

1
+1 Jon,这是唯一一个完全解释如何使用PowerPack评估器的答案。 - Stephen Swensen
不确定是谁给你点了踩,但我用赞平衡了一下,感谢你的有帮助的回答 <3 - Juliet

6

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()

-1

我认为引号已经有了一个.eval()方法。


虽然实际上是 Eval,但我会给你点赞。我不明白为什么你和我的答案都有三个未注释的踩... - J D
1
这个属于哪个命名空间?我没看到它。谢谢! - Jason Kleban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接