F# 从PowerPack计算合成引号表达式时出错

F# 从PowerPack计算合成引号表达式时出错,f#,quotations,F#,Quotations,我试图找出修改报价的方法,然后对其进行评估。在这里,我开始使用basic,并尝试使用Quotences api创建一个Quotence。报价单绑定正常,但我在评估时出错 #r @"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.dll" #r @"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll" open Microsoft.FSharp.Quotations open Microsoft.F

我试图找出修改报价的方法,然后对其进行评估。在这里,我开始使用basic,并尝试使用Quotences api创建一个Quotence。报价单绑定正常,但我在评估时出错

#r @"FSharpPowerPack-2.0.0.0\bin\FSharp.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
#r@“FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.dll”
#r@“FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll”
打开Microsoft.FSharp.quotes
打开Microsoft.FSharp.Linq.QuotationEvaluation
打开Microsoft.FSharp.Linq
让哈德韦=
Expr.Let(
新变量(“x”,类型),
表达式值(10),
Expr.GlobalVar(“x”).Raw)
hardway.evaluntypted()
正在将会话绑定到“FSharp.PowerPack.Linq.dll”。。。
System.Collections.Generic.KeyNotFoundException:字典中不存在给定的键。
在Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer`1 comparer,TValue k,MapTree`2 m)
在d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs中的Microsoft.FSharp.Linq.QuotationEvaluation.convxpr(ConvEnv env,FSharpExpr inp)中:第459行
在d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs中的Microsoft.FSharp.Linq.QuotationEvaluation.convxpr(ConvEnv env,FSharpExpr inp)中:第704行
在d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs中的Microsoft.FSharp.Linq.QuotationEvaluation.convxpr(ConvEnv env,FSharpExpr inp)中:第677行
在d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs中的Microsoft.FSharp.Linq.QuotationEvaluation.CompileImpl[a](e,布尔值相等)处:第837行
在d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs第854行的Microsoft.FSharp.Linq.QuotationEvaluation.Expr.EvalUntyped(FSharpExpr)中
地址:$FSI_0009.main@()
由于错误而停止

我不知道如何使用
GlobalVar
,所以我让其他人回答这个问题。以下是等待更好解决方案的变通方法:

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
let hardway=
设v=新变量(“x”,类型)
Expr.Let(
v
表达式值(10),
Expr.Var(v))
设res=hardway.evaluntypted()//res为10

要使用全局变量实现此功能,您需要这样编写:

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

hardway.EvalUntyped() 
let hardway=
Expr.Let(
全球变量(“x”,类型),
表达式值(10),
(例如GlobalVar(“x”))
hardway.evaluntypted()
Var.Global
Expr.Global
使用一些共享的全局变量字典,F#Quotences库使用这些字典可以获得相同的变量实例,而无需显式传递
Var
值(如Stringer的解决方案)

但是,我认为只创建一次
Var
值,然后保留对该对象的引用(并在表达式中使用相同的对象)会导致更可读的代码,因此我更喜欢Stringer的解决方案

关于我的代码,有几点:

  • 您需要使用
    Var.Global
    而不是
    newvar
    ,因为第二个选项不在全局字典中存储变量
  • 您需要在
    Expr.GlobalVar
    中明确指定类型-如果不这样做,F#将使用
    obj
    ,这是一个不同的变量(它们按名称和类型索引)
有一个自定义的基于反射的求值引擎,它允许您通过传入变量环境来求值合成引号,而无需使变量绑定成为表达式本身的一部分。因此,您可以执行以下操作:

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)
openswensen.Unquote
打开Microsoft.FSharp.quotes
让unquoteway=Expr.Var(Var(“x”,typeof))
让环境=列表的映射[(“x”,框10)]
非报价途径评估(环境)
这很有趣,因为您传入的环境正是整个表达式求值过程中用于所有变量绑定和解析的环境,因此遵循变量范围规则:

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")
let unquoteway=
Expr.NewTuple(
[Expr.Var(新的Var(“x”,typeof))
Expr.Let(新变量(“x”,typeof),Expr.Value(“hello”),Expr.Var(新变量(“x”,typeof)))]
让环境=列表的映射[(“x”,框10)]
非报价途径评估(环境)
//FSI输出:
val unquoteway:Expr=NewTuple(x,Let(x,Value(“hello”),x))
val环境:Map=Map[((“x”,10)]
val-it:obj=(10,“你好”)

太好了,谢谢。第二点很重要,因为如果没有指定类型,将引发相同的异常。