13

I hope I haven't missed something obvious, but I've been playing with F# expressions and I want to evaluate quoted expressions on the fly. For example, I want write something like this:

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

Is there a built-in F# method which can evaluate quoted expressions, or do I have to write my own?

Juliet
  • 80,494
  • 45
  • 196
  • 228

5 Answers5

18

I've implemented a reflection-based Quotation evaluator as part of Unquote (this is a new feature as of version 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)"

I've measured it to be up to 50 times faster than PowerPack's evaluator. This will, of course, vary by scenario. But Unquote is generally magnitudes faster than PowerPack at interpreting expressions.

It also supports many more expressions than PowerPack's evaluator, including VarSet, PropertySet, FieldSet, WhileLoop, ForIntegerRangeLoop, and Quote. In fact, Unquote's evaluator supports all quotation expressions except NewDelegate, AddressSet, and AddressOf all of which I plan on eventually supporting.

johv
  • 4,424
  • 3
  • 26
  • 42
Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
  • Is there a way to use your library for arbitrary unquoting, without the testing part? – Chad Zawistowski Apr 10 '15 at 22:30
  • 2
    @ChadZawistowski yes, there are general functions including `decompile`, `reduce`, `reduceAll`, `eval`, and `unquote` available for arbitrary unquoting (decompilation and evaluation of quotations). – Stephen Swensen Apr 10 '15 at 23:58
9

No, there's no built-in way to compile F# quotations. With the PowerPack LINQ you can convert SOME quotations to .NET System.Linq.Expressions.Expression, and use that to compile them.

Quotations were made to allow other interpretations of code, such as targeting SQL or a GPU card.

However, in posts on hubfs, it's been hinted at that this is a common request and will be looked at.

MichaelGG
  • 9,976
  • 1
  • 39
  • 82
8

You can evaluate an F# quotation using the Eval extension member provided by the FSharp.PowerPack.Linq DLL as follows:

#r "FSharp.PowerPack.Linq.dll"

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

Note that you must open the Linq.QuotationEvaluation namespace to make this extension member available.

There is also a Compile extension member that returns a suspension but it does not appear to improve performance.

J D
  • 48,105
  • 13
  • 171
  • 274
6

Updated in 2016

The Evaluate extension method can now be found in NuGet package 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()
Overlord Zurg
  • 3,430
  • 2
  • 22
  • 27
-1

I think the quotations has got a .eval()-method.

Dario
  • 230
  • 1
  • 2