2010-11-18 6 views
2

引用を変更して評価することを検討しようとしています。ここで私は基本的なことを始めているだけで、Quotations apiを使って見積もりを作成しようとしています。見積もりはOKをバインドしますが、評価する際にエラーが発生します。PowerPackからの合成引用式の評価エラー

#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>[email protected]() 
Stopped due to error 

答えて

3

グローバル変数を使用してこの作業を取得するには、このようにそれを書く必要があると思います(Stringerの解法のように)Varの値を明示的に渡すことなく、同じ変数インスタンスを得ることを可能にするために、F#引用ライブラリが使用する変数の数です。

しかし、Varの値を1回だけ作成してオブジェクトへの参照を保持すると、式で同じオブジェクトを使用すると読みやすいコードになるので、私はStringerのソリューションを好むでしょう。

私のコードについていくつかのポイント:

  • 2番目のオプションは、グローバル辞書に変数を格納していないため、Var.Globalの代わりnew Varを使用する必要があります。
  • タイプを明示的にExpr.GlobalVarに指定する必要があります。そうしないと、F#はobjを使用し、それは異なる変数です(名前はおよびタイプでインデックスされます)。
+0

よかった、ありがとう。 2番目のポイントは重要です。指定されたタイプがなくても、同じ例外がスローされます。 – yanta

2

私はGlobalVarの使い方を知らないので、他の人にこれを回答させてください。ここでは回避策はより良い解決策を待っ中です:

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

hardway.EvalUntyped() 

Var.GlobalExpr.Globalいくつかの共有グローバル辞書を使用します。

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

すてきな回避策、ありがとう。 – yanta

0

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