2010-11-18 3 views
2

인용문을 수정하여 평가하려고합니다. 여기서는 기초부터 시작하여 인용문 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

이 전역 변수를 사용하여 작업을 진행하려면, 당신은 이런 식으로 작성해야 것 :

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

hardway.EvalUntyped() 

Var.GlobalExpr.Global을 일부 공유 글로벌 사전을 사용 F # 인용구 라이브러리가 Var 값을 명시 적으로 전달하지 않고 동일한 변수 인스턴스를 가져올 수 있도록하기 위해 사용하는 변수 중 하나입니다 (Stringer의 솔루션 에서처럼).

그러나 값을 한 번만 생성 한 다음 객체에 대한 참조를 유지하면 표현식에서 동일한 객체를 사용하면 더 읽기 쉬운 코드가되므로 Stringer 솔루션을 선호한다고 생각합니다. 내 코드에 대한

몇 가지 포인트 :

  • 당신은 두 번째 옵션은 글로벌 사전에 변수를 저장하지 않기 때문에 Var.Global 대신 new Var을 사용해야합니다.
  • 형식을 Expr.GlobalVar에 명시 적으로 지정해야합니다. 그렇게하지 않으면 F #은 obj을 사용하며 다른 변수입니다 (이름은 유형으로 인덱싱 됨).
+0

좋아, 고마워. 두 번째 요점은 중요합니다. 지정된 유형이 없으면 같은 예외가 발생합니다. – yanta

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 
+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") 
관련 문제