F# fsharp报价表列表->;Expr处理

F# fsharp报价表列表->;Expr处理,f#,quotations,F#,Quotations,我能做些什么来让下面的工作正常 我需要创建一个函数来接受Expr列表并返回Expr(Expr list->Epxr) 类型数据对象()= 让data=System.Collections.Generic.Dictionary() 成员this.AddValue propertyIndex value=data.Add(propertyIndex,value) 成员this.GetValue propertyIndex= 将data.TryGetValue属性索引与匹配 |(true,value)

我能做些什么来让下面的工作正常

我需要创建一个函数来接受Expr列表并返回Expr(Expr list->Epxr)

类型数据对象()=
让data=System.Collections.Generic.Dictionary()
成员this.AddValue propertyIndex value=data.Add(propertyIndex,value)
成员this.GetValue propertyIndex=
将data.TryGetValue属性索引与匹配
|(true,value)->value
|(false,824;)->框“未找到属性”
...
(有趣的args->
List.iteri(fun i arg->data.AddValue i)
资料
@@>)
我创建了DataObject类型以在中添加args的值。但不知何故,我无法让代码在不同的args(args.[0]…args.[I])之间迭代。我得到的信息是:

变量“arg”绑定在引号中,但用作拼接表达式的一部分。这是不允许的,因为它可能超出其范围

如果我显式地访问args(args[0]、args[1]、…),解决方案就可以工作,但一旦我尝试添加迭代,我就会遇到问题。因为arg列表的长度是灵活的,所以这对我来说不是一个可行的解决方案

我尝试过不同的方法,但没有成功。有什么解决办法吗

[编辑]

在我的解决方案中添加Tomas的反馈给我带来了以下好处:

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))) @@>))
类型数据对象(值:obj[])=
让propertyMap=新映射(值|>Seq.mapi(乐趣i值->(i,值)))
成员this.GetValue propertyIndex:obj=
将propertyMap.TryFind propertyIndex与匹配
|一些(值)->值
|无->框“未找到属性”
(有趣的args->
让boxedArgs=
args |>List.map(有趣的arg->
将arg与
|QUOTES.Patterns.Var->
如果变量类型=类型,则
否则,如果变量类型=类型,则
否则,如果变量类型=类型,则
其他的
failwith(“Aha:+var.Type.ToString())
|->failwith(“未知表达式作为参数”))
))

这很有效!唯一的问题是我想摆脱如果。。。否则将无法获得正确的转换。有什么想法吗?

这是个棘手的问题!为了理解代码不起作用的原因,您需要清楚地区分两个级别——在一个级别(meta),您编写引用,在另一个级别(base),您使用数据对象运行一些代码

代码不起作用的原因是,
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() @> )

嗨,托马斯。谢谢你的投入,这让我更进一步了。到目前为止,我已经用答案编辑了这个问题。你对if..then结构也有一些想法吗?(参见有问题的编辑)关于编辑,我认为您可以将
if
替换为
Expr.compresse(arg,typeof)
——这将为您提供一个表示任何其他表达式
arg
装箱的表达式。
(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() @> )
<@@ let d = new DataObject()
    d.AddValues(%(Expr.NewArray(typeof<obj>, args)))
    d @@>