2013-11-09 6 views
2

다음 작업을하려면 어떻게해야합니까?fsharp 인용구 Expr 목록 -> Expr 처리

Expr 목록을 받아들이고 Expr (Expr list -> Epxr)을 반환하는 함수를 만들어야합니다.

type DataObject() = 
    let data = System.Collections.Generic.Dictionary<int, obj>() 
    member this.AddValue propertyIndex value = data.Add(propertyIndex, value) 
    member this.GetValue propertyIndex = 
     match data.TryGetValue propertyIndex with 
     | (true, value) -> value 
     | (false, _) -> box "property not found" 

... 
(fun args -> 
    <@@ 
     let data = new DataObject(values) 
     args |> List.iteri (fun i arg -> data.AddValue i <@@ (%%arg) : string @@>) 
     data 
    @@>) 

난의 인수의 값을 추가하는 데이터 객체 유형을 만들었다. 어쨌든 I는 다른 인수를 반복 코드 그럭저럭 수 (인수한다. [0] ... 인수. [I]). 내가받는 메시지는 다음과 같습니다.

'arg'변수는 인용 부호로 묶이지 만 연결 된 표현식의 일부로 사용됩니다. 범위를 벗어날 수 있기 때문에 허용되지 않습니다.

나는 명시 적으로 인수에 액세스하는 경우 (인수를. [0], 인수. [1], ...) 솔루션은 작동하지만 곧 내가 문제로 실행 반복을 추가하려고한다. args의 목록은 길이가 유연하기 때문에 이것은 실현 가능한 해결책이 아닙니다.

다른 방법을 시도했지만 불만족 스럽습니다. 해결책이 있습니까?

type DataObject(values: obj []) = 
    let propertyMap = new Map<int, obj>(values |> Seq.mapi (fun i value -> (i, value))) 
    member this.GetValue propertyIndex : obj = 
     match propertyMap.TryFind propertyIndex with 
     | Some(value) -> value 
     | None  -> box "property not found" 

(fun args -> 
    let boxedArgs = 
     args |> List.map (fun arg -> 
      match arg with 
      | Quotations.Patterns.Var var -> 
       if var.Type = typeof<int> then 
        <@@ (box (%%arg: int)) @@> 
       else if var.Type = typeof<string> then 
        <@@ (box (%%arg: string)) @@> 
       else if var.Type = typeof<System.Guid> then 
        <@@ (box (%%arg: System.Guid)) @@> 
       else 
        failwith ("Aha: " + var.Type.ToString()) 
      | _ -> failwith ("Unknown Expr as parameter")) 
     <@@ new DataObject(%%(Expr.NewArray(typeof<obj>, boxedArgs))) @@>)) 

그리고이 작품 :

[편집]

내 솔루션에 토마스의 피드백을 추가하는 것은 저에게이을 제공합니다! 유일한 것은 올바른 전환을 얻기 위해 if ... else 구조를 제거하고 싶다는 것입니다. 어떤 아이디어?

+0

, 당신이 대해서 typeof'Expr.Coerce (ARG, )'와'if'를 대체 할 수 있다고 생각 - 그것은 당신에게 다른 표현'인수의 권투를 나타내는 식을 제공해야 '. –

답변

6

이것은 까다로운 질문입니다. 코드가 작동하지 않는 이유를 이해하려면 한 레벨 (메타)에서 인용문을 작성하고 다른 레벨 (베이스)에서 데이터 오브젝트를 사용하여 일부 코드를 실행하는 두 레벨을 명확히 구분해야합니다.

코드가 작동하지 않는 이유는 args이 메타 레벨의 표현식 목록이며 사용자가 기본 레벨에서 반복을 시도하기 때문입니다. 반복은 메타 수준에서 발생해야합니다.

이 문제를 해결하는 한 가지 방법은 메타 수준에서 반복을 수행하고 모든 인수에 AddValue을 호출하는 함수 목록을 생성하는 것입니다. 그런 다음 함수를 구성 할 수 있습니다.

(fun args -> 
    // Given arguments [a0; a1; ...] Generate a list of functions: 
    // 
    // [ fun data -> data.AddValue 0 a0; data ] 
    // [ fun data -> data.AddValue 1 a1; data ... ] 
    args 
    |> List.mapi (fun i arg -> 
     <@ fun (data:DataObject) -> data.AddValue i (%%arg : string); data @>) 

    // Compose all the functions just by calling them - note that the above functions 
    // take DataObject, mutate it and then return it. Given [f0; f1; ...] produce: 
    // 
    // ... (f1 (f0 (new DataObject()))) 
    // 
    |> List.fold (fun dobj fe -> <@ (%fe) (%dobj) @>) <@ new DataObject() @>) 

이것은 재미 있지만 실제로 복잡해집니다. 실제로 AddValues 메서드를 데이터 객체에 추가하고 (obj[]) Expr.NewArray을 사용하여 메타 수준의 모든 매개 변수 값을 포함하는 단일 배열 (기본 수준에서)을 만들면 훨씬 쉽게 작업 할 수 있습니다.) : 편집에 관한

<@@ let d = new DataObject() 
    d.AddValues(%(Expr.NewArray(typeof<obj>, args))) 
    d @@> 
+0

안녕하세요 토마스. 의견을 보내 주셔서 감사합니다. 몇 단계 더 나아갔습니다. 지금까지 솔루션으로 질문을 편집했습니다. 당신은 또한 if..then constrution에 대한 아이디어가 있습니까? (문제의 편집 참조) – BBL

관련 문제