Ошибка при вычислении выражения синтетической цитаты из PowerPack - PullRequest
2 голосов
/ 18 ноября 2010

Я пытаюсь выяснить, как изменить цитаты, а затем оценить их. Здесь я начинаю основную и просто пытаюсь создать цитату, используя API Quotations. Цитата связывает ОК, но я получаю ошибку при оценке.

#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

Ответы [ 3 ]

3 голосов
/ 18 ноября 2010

Чтобы это работало с использованием глобальных переменных, вам нужно написать это так:

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

hardway.EvalUntyped() 

Var.Global и Expr.Global используют некоторый общий глобальный словарь переменных, который использует библиотека цитат F #, чтобы сделать возможным получение одного и того же экземпляра переменной без явной передачи значений Var (как в решении Stringer).

Однако я думаю, что создание значения Var только один раз, а затем сохранение ссылки на объект (и использование того же объекта в выражении) приводит к более читаемому коду, поэтому я бы предпочел решение Stringer.

Несколько замечаний по поводу моего кода:

  • Вам нужно использовать Var.Global вместо new Var, потому что второй параметр не сохраняет переменную в глобальном словаре.
  • Вам необходимо явно указать тип в Expr.GlobalVar - если вы этого не сделаете, F # будет использовать obj, а это другая переменная (они индексируются по именам и type).
2 голосов
/ 18 ноября 2010

Я не знаю, как использовать 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
0 голосов
/ 08 июля 2011

Unquote имеет пользовательский механизм оценки, основанный на отражениях, который позволяет вам оценивать синтетические цитаты, передавая переменную среду, а не делать привязку переменной частью самого выражения.Таким образом, вы можете сделать следующее:

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)

Это интересно, потому что среда, в которую вы переходите, является той самой средой, которая используется для всех привязок и разрешений переменных во время вычисления выражения, поэтому соблюдаются правила переменной области видимости:

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")
...