开发者

Error evaluating synthetic quotation expression from PowerPack

开发者 https://www.devze.com 2023-01-25 11:07 出处:网络
I am trying to figure out to modify quotations and then evaluate them. Here I am starting basic and just trying to create a quotation using the Quotations api. The quotation binds OK, but I get an err

I am trying to figure out to modify quotations and then evaluate them. Here I am starting basic and just trying to create a quotation using the Quotations api. The quotation binds OK, but I get an error when evaluating.

#r @"FSharpPowerPack-2.0.0.0\bin\FShar开发者_如何学编程p.PowerPack.dll"
#r @"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll"

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
open Microsoft.FSharp.Linq

let hardway = 
    Expr.Let(
        new Var("x", typeof<int>),
        Expr.Value(10),
        Expr.GlobalVar("x").Raw)

hardway.EvalUntyped()


Binding session to 'FSharp.PowerPack.Linq.dll'...
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer`1 comparer, TValue k, MapTree`2 m)
   at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 459
   at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 704
   at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 677
   at Microsoft.FSharp.Linq.QuotationEvaluation.CompileImpl[a](a e, Boolean eraseEquality) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 837
   at Microsoft.FSharp.Linq.QuotationEvaluation.Expr.EvalUntyped(FSharpExpr ) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 854
   at <StartupCode$FSI_0009>.$FSI_0009.main@()
Stopped due to error


To get this working using global variables, you'd need to write it like this:

let hardway =  
    Expr.Let( 
        Var.Global("x", typeof<int>), 
        Expr.Value(10), 
        (Expr.GlobalVar<int>("x")) ) 

hardway.EvalUntyped() 

Var.Global and Expr.Global use some shared global dictionary of variables that the F# quotations library uses to make it possible to get the same variable instance without explicitly passing Var values around (as in Stringer's solution).

However, I think that creating Var value only once and then keeping a reference to the object (and ussing the same object in the expression) leads to more readable code, so I'd prefer Stringer's solution.

A few points about my code:

  • You need to use Var.Global instead of new Var because the second option doesn't store the variable in the global dictionary.
  • You need to specify the type explicitly in Expr.GlobalVar - if you don't do that, F# will use obj and that's a different variable (they are indexed by name and type).


I don't know how to use GlobalVar so I let others answer on this. Here's a workaround in waiting for a better solution:

let hardway = 
    let v = new Var("x", typeof<int>)
    Expr.Let(
        v,
        Expr.Value(10),
        Expr.Var(v))

let res = hardway.EvalUntyped() // res is 10


Unquote has a custom reflection-based evaluation engine which allows you to evaluate synthetic quotations by passing in a variable environment rather than needing to make the variable binding part of the expression itself. So you could do the following:

open Swensen.Unquote
open Microsoft.FSharp.Quotations

let unquoteway = Expr.Var(Var("x", typeof<int>))
let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)

This is interesting because the environment you pass in is the very environment used for all variable bindings and resolutions throughout the expression evaluation so variable scoping rules are honored:

let unquoteway = 
    Expr.NewTuple(
       [Expr.Var(new Var("x", typeof<int>))
        Expr.Let(new Var("x", typeof<string>), Expr.Value("hello"), Expr.Var(new Var("x", typeof<string>)))])

let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)

//FSI output:
val unquoteway : Expr = NewTuple (x, Let (x, Value ("hello"), x))
val environment : Map<string,obj> = map [("x", 10)]
val it : obj = (10, "hello")
0

精彩评论

暂无评论...
验证码 换一张
取 消