2

見積もりを修正してから評価する方法を見つけようとしています。ここでは、基本的なことから始めて、Quotations API を使用して見積もりを作成しようとしています。引用符は問題なくバインドできますが、評価時にエラーが発生します。

#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
4

3 に答える 3

3

グローバル変数を使用してこれを機能させるには、次のように記述する必要があります。

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

hardway.EvalUntyped() 

Var.GlobalExpr.GlobalF# quotes ライブラリが使用する変数の共有グローバル ディクショナリを使用して、値を明示的に渡すことなく同じ変数インスタンスを取得できるようにします(Varストリンガーのソリューションのように)。

ただし、Var値を一度だけ作成してからオブジェクトへの参照を保持する (および式で同じオブジェクトを使用する) と、コードが読みやすくなると思うので、Stringer のソリューションを使用したいと思います。

私のコードに関するいくつかのポイント:

  • 2 番目のオプションは変数をグローバル ディクショナリに格納しないため、Var.Global代わりに使用する必要があります。new Var
  • 型を明示的に指定する必要があります。指定Expr.GlobalVarしない場合、F# は別の変数を使用します (名前obj型によってインデックスが付けられます)。
于 2010-11-18T15:17:25.570 に答える
2

使い方がわからない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
于 2010-11-18T11:07:56.360 に答える
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")
于 2011-07-08T19:17:54.787 に答える