Как создать дерево выражений Linq с помощью F # lambda?

Здесь что можно сделать в С# -

var two = 2;
System.Linq.Expressions.Expression<System.Func<int, int>> expr = x => x * two;
expr.Compile().Invoke(4); // returns 8

Я хочу сделать точный эквивалент в F #. Вот что я пробовал, но не компилировал -

let two = 2
let expr = (fun x -> x * two) : System.Linq.Expressions.Expression<System.Func<int, int>>
expr.Compile().Invoke(4) // desired to return 8

Возможно, возможно, компиляция завершится неудачно в строке 2 со следующей ошибкой -

"This function takes too many arguments, or is used in a context where a function is not expected."
let expr = (fun x -> x * two) : System.Linq.Expressions.Expression<System.Func<int, int>>
            ^^^^^^^^^^^^^^^^

Ответ 1

Я не уверен, почему вы хотите избежать использования котировок F # - под крышкой они почти такие же, как деревья выражений С#, и если вы хотите создать дерево выражений в F #, то компилятор будет использовать котировки под крышкой в ​​любом случае...

В любом случае, вы можете сделать это, не записывая явный <@ .. @>, потому что компилятор может автоматически указывать функцию, когда она передается в качестве аргумента для метода. Итак, вы можете сделать:

type Expr = 
  static member Quote(e:Expression<System.Func<int, int>>) = e

let two = 2
let expr = Expr.Quote(fun x -> x * two) 
expr.Compile().Invoke(4) // desired to return 8

EDIT: Однако это действительно компилируется в котировку F #, заключенную в вызов, который преобразует его в дерево выражений С#. Итак, в конце концов, вы получите то же самое, что написано:

open Microsoft.FSharp.Linq.RuntimeHelpers

let two = 2
let expr = 
  <@ System.Func<_, _>(fun x -> x * two) @>
  |> LeafExpressionConverter.QuotationToExpression 
  |> unbox<Expression<Func<int, int>>>
expr.Compile().Invoke(4) // desired to return 8