The following code is extracted from an application and adapted to highlight the issue as easy as possible
module Mo
open System
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers
open System.Linq.Expressions
type Type() =
member _.Prop1 with get() = 1
member _.Prop2 with get() = 2
let toFunc<'t when 't :> Type>(filter: 't -> Expr<bool>) =
let xp = <@ Func<'t, bool>(fun (t: 't) -> %(filter t) && t.Prop2 = 2) @>
LeafExpressionConverter.QuotationToExpression xp |> unbox<Expression<Func<'t, bool>>>
let getFunc (i: int) =
let filter (t: Type) = <@ t.Prop1 = i @>
toFunc filter
the problem is in the line
let xp = <@ Func< 't, bool>(fun (t: 't) -> %(filter t) && t.Prop2 = 2) @>
The compiler complains in fun (t: 't) as follows:
Error FS0446
The variable 't' is bound in a quotation but is used as part of a spliced expression.
This is not permitted since it may escape its scope.
The intent is to compose quotations into a filter Linq expression. Is there a (alternative) way to do this?
EDIT:
Some more context looks necessary:
The returned Func expression is later passed to Azure.Data.Tables.TableClient.Query(). Unfortunately this method doesn't support expressions containing function calls.
Converting filter to a quoted function (as suggested by Fyodor) was my first version, but I had to abandon it because of this requirement of the Azure Tables SDK.
So the question becomes :
Is it possible to achieve the result of an expression that doesn't contain calls to external method/function?
You're mixing up your variables between quotation realm and "regular" realm.
filteris not a quoted function. It's a regular function that returns a quotation. Regular functions get regular parameters, quoted functions get quoted parameters.The
tparameter here:That's a quoted parameter. It's defined inside a quotation.
And yet, you're trying to pass its value to the
filterfunction. But at the moment of constructing the quotation, the parametertdoesn't have a value yet! Only when you're done constructing the quotation, then compile it to IL, and then call it, - only then will the parameterthave a value, allowing you to call thefilterfunction. But you need the result offilterfunction to finish constructing the quotation in the first place!The most straightforward fix is to make
filtera quoted function. Then you can splice it into the quotation, and then pass the parametertto the result of splicing: