Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reflection 使用代码引用和表达式树构建AST_Reflection_F# - Fatal编程技术网

Reflection 使用代码引用和表达式树构建AST

Reflection 使用代码引用和表达式树构建AST,reflection,f#,Reflection,F#,我在构建表达式树时遇到一些问题。当使用代码引用时,我也可以做同样的事情,但到目前为止,我还没有通过表达式来做这件事 首先看一下我通过代码引用来实现这一点的方法 open Microsoft.FSharp.Quotations open Microsoft.FSharp.Quotations.Patterns open Microsoft.FSharp.Quotations.DerivedPatterns type Container<'a> = Co

我在构建表达式树时遇到一些问题。当使用代码引用时,我也可以做同样的事情,但到目前为止,我还没有通过表达式来做这件事

首先看一下我通过代码引用来实现这一点的方法

    open Microsoft.FSharp.Quotations
    open Microsoft.FSharp.Quotations.Patterns
    open Microsoft.FSharp.Quotations.DerivedPatterns

    type Container<'a> = Container of 'a
    type FromD<'a> = {a: Container<'a>; b: Container<'a>}
    type ToD<'a> = {a: Container<'a>; b: Container<'a>}

    let private eval e = QuotationEvaluator.Evaluate e

    let f1 f =
        let ex =
            <@
                fun (x:FromD<'a>) ->
                {
                    a = f x.a;
                    b = f x.b
                } 
                : ToD<'b>
            @>
        eval ex
现在,一些测试代码将
从d
转换为
ToD
,并在
容器上应用转换

    let transform (Container (v:'a)) : Container<'b> = Container (sprintf "%A" v)

    [<Test>]
    let ``test F1`` () =
        let r1 = f1 transform {a = Container true; b = Container true}
        let r2 = f1 transform {a = Container 1; b = Container 2}
        printfn "F1: %A, F1: %A" r1 r2
还有一些测试代码

let ``test F2`` () =
    let r3 = (f2<FromD<bool>, ToD<string>> transform) {a = Container true; b = Container true}
    printfn "R3 %A" r3 
因此,在构造表达式树时似乎存在一些问题,因为类型推断器说我的函数有一个
bool
type参数,但实际参数是
object

现在我可以通过这样重写函数来克服这个问题

let f2<'x, 't> f = 
    let xt = typeof<'x>
    let tt = typeof<'t>
    let ps = nameMap xt
    let x = Var("x", xt)
    let vx = Expr.Var(x)
    let fnv = Expr.ValueWithName(f, typeof<Container<bool> -> Container<string>>, "f")
    let ex = 
        Expr.Lambda(x,
            Expr.NewRecord(tt,
                [
                    Expr.Application(fnv, Expr.PropertyGet(vx, ps.Item "a", []))
                    Expr.Application(fnv, Expr.PropertyGet(vx, ps.Item "b", []))
                ])) 

    let ex2 : Expr<'x -> 't> = ex |> Expr.Cast
    let ex3 = eval ex2
    ex3

有人知道发生了什么吗?

f2
的类型以
'x->'t
结尾,因为这正是您在这一行中指定它的方式:

let ex2 : Expr<'x -> 't> = ex |> Expr.Cast
这将在第一次应用程序之前为您提供正确的类型

但要小心
由于您的所有处理都是在运行时进行的,因此编译器无法保证您在所有位置的类型安全。因此,你必须自己小心防范它们。下面是代码所依赖的一些(尽管可能不是全部)编译时不可执行的东西:

  • 类型
    'x
    必须是一条记录,其字段名为
    a
    b
    类型为
    'a
  • 类型
    't
    必须是一个记录,它有两个字段,分别命名为
    a
    b
    ,按特定顺序声明,并且都有类型
    'b
  • 这样的设计在我看来有点摇摆不定。也许如果你描述了你最初的问题(最好是一个单独的问题),有人会建议一个更优雅的解决方案

    如果您只是想“超越记录”,我可能会考虑一个不太雄心勃勃的解决方案,例如:

    let fromDMap f (fromD: FromD<_>) : ToD<_> = { a = f fromD.a; b = f fromD.b }
    
    // Usage:
    let r3 = fromDMap transform {a = Container true; b = Container true}
    
    let fromDMap f(fromD:fromD):ToD={a=f fromD.a;b=f fromD.b}
    //用法:
    设r3=fromDMap变换{a=Container true;b=Container true}
    
    当然,如果您想要创建一个“通用”函数来映射任意类型的同名字段,那么这种方法将不起作用。但是,我敢说这样的函数有点过于通用



    p.S.您的函数
    transform
    的声明类型比函数的实际类型更通用。声明的返回类型是
    ContainerIt,它的类型是
    'x->'t
    ,因为这正是您强制转换它的方式。编译器完全按照您的要求执行。至于将
    f
    的类型固定为
    obj
    ,那是因为代码中没有任何东西可以将编译器指向
    f
    的类型。@FyodorSoikin是的,当然-但这只是bc,否则我甚至无法编译它。因此,只要我能够用实际工作的签名
    (Container)->(FromD)
    来表示函数,我就不受此实现的约束,因此我愿意接受其他建议。;-)不,那对我不起作用。我不能这样定义它,因为
    f2
    实际上比您在示例中看到的要灵活得多(因此也需要通过表达式而不是引用来构造它)。我想要的是一个函数
    f2::g[j[a]->(j[a]->j[b])->h[j[b]
    (Haskell语法),但这不能用F的签名来表达。因此,放置
    (容器)
    不是一个选项,从你那里得到一个提示,我就解决了问题。函数签名必须是这样的
    let f2 transform
    您不能要求类型参数本身就是具有自己类型参数的类型构造函数。这被称为“高级类型”(与“高阶函数”相比),而F#没有这些类型。
    let f2<'x, 't> f = 
        let xt = typeof<'x>
        let tt = typeof<'t>
        let ps = nameMap xt
        let x = Var("x", xt)
        let vx = Expr.Var(x)
        let fnv = Expr.ValueWithName(f, typeof<Container<bool> -> Container<string>>, "f")
        let ex = 
            Expr.Lambda(x,
                Expr.NewRecord(tt,
                    [
                        Expr.Application(fnv, Expr.PropertyGet(vx, ps.Item "a", []))
                        Expr.Application(fnv, Expr.PropertyGet(vx, ps.Item "b", []))
                    ])) 
    
        let ex2 : Expr<'x -> 't> = ex |> Expr.Cast
        let ex3 = eval ex2
        ex3
    
    System.ArgumentException : Argument types do not match
    at System.Linq.Expressions.Expression.Constant (System.Object value, System.Type type) [0x00049] in <4a648327db854c86ab0ece073e38f4b3>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.LetRecConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Core.FSharpOption`1[T] letrec, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00185] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.ConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.LetRecConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Core.FSharpOption`1[T] letrec, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x02065] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.ConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvExprs@703.Invoke (Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] mapping, Microsoft.FSharp.Collections.FSharpList`1[T] x) [0x0003f] in <57acd2f6dff9fae1a7450383f6d2ac57>:0
    at Microsoft.FSharp.Collections.ListModule.Map[T,TResult] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] mapping, Microsoft.FSharp.Collections.FSharpList`1[T] list) [0x00001] in <57acd2f6dff9fae1a7450383f6d2ac57>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.ConvExprs (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Collections.FSharpList`1[T] es) [0x00007] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.LetRecConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Core.FSharpOption`1[T] letrec, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x020e6] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.ConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.LetRecConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Core.FSharpOption`1[T] letrec, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x027f0] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.ConvExpr (FSharp.Quotations.Evaluator.QuotationEvaluationTypes+ConvEnv env, Microsoft.FSharp.Quotations.FSharpExpr inp) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.Conv[a] (a e, System.Boolean eraseEquality) [0x0001d] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.CompileImpl[a] (a e, System.Boolean eraseEquality) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluationTypes.Compile[a] (a e) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at FSharp.Quotations.Evaluator.QuotationEvaluator.Evaluate[T] (Microsoft.FSharp.Quotations.FSharpExpr`1[T] e) [0x00001] in <56703c1ea378c767a74503831e3c7056>:0
    at tst.f2[x,t] (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] f) [0x000f5] in <5823081418eafa12a745038314082358>:0
    at tst.test F2 () [0x00005] in <5823081418eafa12a745038314082358>:0
    at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
    at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in <8cd55ece525b4760b63de40980e005aa>:0
    
    let ex2 : Expr<'x -> 't> = ex |> Expr.Cast
    
    let f2<'x, 't, 'a, 'b> (f: Container<'a> -> Container<'b>) = 
        ...
    
    let fromDMap f (fromD: FromD<_>) : ToD<_> = { a = f fromD.a; b = f fromD.b }
    
    // Usage:
    let r3 = fromDMap transform {a = Container true; b = Container true}