This project is read-only.
3
Vote

Eval of nested quotations

description

F# quotation evaluation does not support nested quotations.
(of interest for multi-staged uses, encoding two-level lambda terms as a transformation).
As far as I can see, supporting such a feature would require substituting the variable binding
to the expression inside of the quotation - so potentially easily handled.
 
open Microsoft.FSharp.Linq.QuotationEvaluation
let c2 = <@ <@ 2 @> @>
let _ = c2.Eval()
 

Unhandled Exception: System.NotSupportedException: Could not convert the following F# Quotation to a LINQ Expression Tree

Quote (Value (2))

 
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(FSharpMap2 env, FSharpExpr inp)
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(FSharpMap
2 env, FSharpExpr inp)
at Microsoft.FSharp.Linq.QuotationEvaluation.Compile[a](a e)
at Microsoft.FSharp.Linq.QuotationEvaluation.Expr1.Eval[T](FSharpExpr1 )
at <StartupCode$ConsoleApplication1>.$Ms.main@() in

comments

dmilom wrote Jun 14, 2010 at 11:51 PM

Hi Nikolaj,
if you want to experiment with this stuuf, I point you to an existence of QuotationEvaluation.LinqExpressionHelper. It looks like <@ .. @...@ ..@> can be rewritten into <@ ... (...) |> QuotationEvaluation.LinqExpressionHelper @> which would then compile normally.

NikolajBjorner wrote Jun 15, 2010 at 4:45 AM

I am not sure if I follow:

The following code throws an exception.

let c1 = <@ 0 |> LinqExpressionHelper @>
do Printf.printf "%O\n" (c1)
do Printf.printf "%O\n" (c1.Eval())

Unhandled Exception: System.ArgumentException: Expression of type 'System.Int32'
cannot be used for return type 'System.Linq.Expressions.Expression1[System.Int32]'
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection
1 parameters)
at System.Linq.Expressions.Expression.Lambda(Type delegateType, Expression body, IEnumerable1 parameters)
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in C:\tmp\fsharppowerpack-46549\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 716
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExprs@829.Invoke(FSharpExprinp) in C:\tmp\fsharppowerpack-46549\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 829
at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList
1 cons, FSharpFunc2 f, FSharpList1 x)....

Also "fixing" the main body of ConvExpr does not work directly:
    | Patterns.Quote e -> 
      Expression.Quote (ConvExpr env (MakeFakeExpression(e))) |> asExpr
(with an without MakeFakeExpression, which seems to me as a no-op anyway, throws)

Unhandled Exception: System.ArgumentException: Expression of type 'System.Int32'
cannot be used for return type 'System.Linq.Expressions.Expression1[System.Int
32]'
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, E
xpression& body, ReadOnlyCollection
1 parameters)
at System.Linq.Expressions.Expression.Lambda(Type delegateType, Expression bo
dy, IEnumerable1 parameters)
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr
inp) in C:\tmp\fsharppowerpack-46549\May2010\src\FSharp.PowerPack.Linq\Linq.fs:
line 716
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExprs@829.Invoke(FSharpExprinp) in C:\tmp\fsharppowerpack-46549\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 829
at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList
1 cons, FSharpFunc2 f, FSharpList1 x)

I am not familiar with the Linq compiler, so would appreciate your advice before spending cycles digging (the wrong places).

Thanks,

Nikolaj

dmilom wrote Jun 16, 2010 at 4:36 PM

Sorry - I led you down a wrong path: LinqExpressionHelper can only handle a degenerate case of Foo(Linq.Expression<T>) applied to a value of type T in quotations - I was somehow thinking there is more to it.

Apologies,
Dmitry

NikolajBjorner wrote Jun 17, 2010 at 7:15 PM

Hmm..
Simple solutions seem to be elusive, at least to me.
The following comes close (for nested quotes of type int):

| Patterns.Quote e ->
Expression.Constant(Expr.Cast<int>(e)) |> asExpr
but it depends on a Cast into Expr<T> from a function that works on untyped Exprs, and it disregards the environment with free variables.

NikolajBjorner wrote Jun 18, 2010 at 7:21 AM

Continuing the fun, this time with Michal Moskal, reflection deals with the case of closed expressions:
    | Patterns.Quote e -> 
      let vars = e.GetFreeVars()
      if vars.Count() = 0 then 
        let cast_method = typeof<Expr>.GetMethod("Cast").MakeGenericMethod [|e.Type |]
        let e1 = cast_method.Invoke(null, [| e |])
        Expression.Constant(e1) |> asExpr
The case with free variables in the body is also doable, but currently requires a few additional hoops.

wrote Jan 8, 2011 at 2:29 PM

wrote Feb 28, 2011 at 11:28 PM

wrote Mar 21, 2011 at 11:23 PM

wrote Feb 22, 2013 at 12:25 AM