Say we have a simple quote from F #:
type Pet = {Name: string}
let exprNonGeneric = <@@ System.Func (fun (x: Pet) -> x.Name) @@>
The resulting quote looks like this:
val exprNonGeneri: Expr =
NewDelegate (System.Func`2 [[FSI_0152 + Pet, FSI-ASSEMBLY, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null], [System.String, mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]],
x, PropertyGet (Some (x), System.String Name, []))
Now I want to generalize it, so instead of the type βPetβ and the property βNameβ, I could use an arbitrary type and the method / property defined on it. Here is what I am trying to do:
let exprGeneric <'T,' R> f = <@@ System.Func <'T,' R> (% f) @@>
let exprSpecialized = exprGeneric <Pet, string> <@ (fun (x: Pet) -> x.Name) @>
The resulting expression is now different:
val exprSpecialized: Expr =
NewDelegate (System.Func`2 [[FSI_0152 + Pet, FSI-ASSEMBLY, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null], [System.String, mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]],
delegateArg,
Application (Lambda (x,
PropertyGet (Some (x), System.String Name, [])),
delegateArg))
As you can see, the difference between the first and second expression is that in the first case, the top-level NewDelegate expression contains a PropertyGet, and the second expression wraps the PropertyGet in the Application / Lambda expression. And when I pass this expression to the external code, it does not expect such an expression structure and fails.
So, I need to somehow build a generalized version of the quote, so when it becomes specialized, the resulting quote is an exact match <@@ System.Func (fun (x: Pet) β x.Name) @@>. Is it possible? Or is it just a choice to manually apply pattern matching to the generated quote and convert it to what I need?
UPDATE As a workaround, I implemented the following adapter:
let convertExpr (expr: Expr) =
match expr with
| NewDelegate (t, darg, appl) ->
match (darg, appl) with
| (delegateArg, appl) ->
match appl with
| Application (l, ldarg) ->
match (l, ldarg) with
| (Lambda (x, f), delegateArg) ->
Expr.NewDelegate (t, [x], f)
| _ -> expr
| _ -> expr
| _ -> expr
Performs this task - now I can convert the expression from 1st to 2nd form. But I am interested to know if this can be achieved in a simple way, without crossing the expression trees.