10

I can convert a quotation of type Expr<'a -> 'b> to a Linq expression via the following snippet:

/// Converts a F# Expression to a LINQ Lambda
let toLambda (exp:Expr) =
    let linq = exp.ToLinqExpression() :?> MethodCallExpression
    linq.Arguments.[0] :?> LambdaExpression

/// Converts a Lambda quotation into a Linq Lamba Expression with 1 parameter
let ToLinq (exp : Expr<'a -> 'b>) =
    let lambda = toLambda exp
    Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)

Now I want to convert a quotation of type Expr<'a * 'b -> 'c> or maybe even Expr<'a -> 'b -> 'c> to a Linq Lambda Expression of type Expression<Func<'a,'b'c>>.

How can I do this?

Regards, forki

forki23
  • 2,784
  • 1
  • 28
  • 42
  • where is the method `ToLinqExpression()` defined? I can't seem to find it – Maslow Mar 14 '15 at 20:06
  • 1
    `expr.ToLinqExpression()` is now in `F#` as `Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression expr` – Maslow Mar 22 '15 at 15:10
  • To clarify: This is available as of F# 3.0; given the date of the original question, probably even 2.0 already. – TeaDrivenDev Dec 26 '15 at 13:23

1 Answers1

13

I'm not sure if this is directly supported by the LINQ modules available in the F# PowerPack. However, you can implement your own post-processing of the LINQ expression produced by F# libraries to turn it into a C# lambda function of the usual form:

The following function takes a LINQ expression which is constructed as multiple nested LambdaExpression expressions of a single parameter (that is, the structure produced by F# translator) and returns a list of parameters and body of the inner-most expression:

let rec translateExpr (linq:Expression) = 
  match linq with
  | :? MethodCallExpression as mc ->
      let le = mc.Arguments.[0] :?> LambdaExpression
      let args, body = translateExpr le.Body
      le.Parameters.[0] :: args, body
  | _ -> [], linq

Now you can use it to get an ordinary Func delegate out of type such as int -> int -> int -> int like this:

let linq = (<@@ fun a b c -> (a + b) * c @@>).ToLinqExpression()
let args, body = translateExpr liq
let f = Expression.Lambda<Func<int, int, int, int>>
          (body, args |> Array.ofSeq)
f.Compile().Invoke(10, 11, 2)
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • 2
    `(<@@ fun a b c -> (a + b) * c @@>).ToLinqExpression()` is now in `F#` as `Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression (<@@ fun a b c -> (a + b) * c @@>)` – Maslow Mar 22 '15 at 15:11