code语录:如何获取的lambda函数内部变量? [英] Code Quotations: how to access variables of a lambda function internally?

查看:141
本文介绍了code语录:如何获取的lambda函数内部变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在运行时组建了一个code报价lambda函数。下面是一个高度简化的例子来说明这一点。我已取得了在运行时错误(未编译时)每次尝试下:

I am having trouble at runtime in putting together a code quotation for a lambda function. Below is a highly simplified example to demonstrate the point. I have given the errors yielded at runtime (not compile time) underneath each attempt:

open FSharp.Quotations

// First Attempt
let exprFun (a:int) (b:int) :Expr<int> = <@ a+b @>
let q1:Expr<int->int->int> = <@ fun x y -> %(exprFun x y) @>        // NB: need to pass around and access `x` & `y` within a nested quotation expression
// error: The variable 'x' is bound in a quotation but is used as part of a spliced expression. This is not permitted since it may escape its scope. 

// Second Attempt
let x = new Var("x", typeof<int>)
let xe = Expr.Cast<int> ( Expr.Var(x) )
let y = new Var("y", typeof<int>)
let ye = Expr.Cast<int> ( Expr.Var(y) )
let q2 = Expr.Cast< int->int->int > ( Expr.Lambda(x, Expr.Lambda(y, <@ %(exprFun %xe %ye) @> )) )
// System.InvalidOperationException: first class uses of '%' or '%%' are not permitted

我充分意识到,这个例子不需要的 X'放大器; Ÿ变量传递给 exprFun 但是在我的现实世界的例子,我需要这种行为,因为我这些变量传递到一个复杂的递归函数,将返回code报价/ EX pression本身。

I am fully aware that this example doesn't require that the x & y variables be passed to exprFun but in my real-world example I need this behaviour as I am passing these variables into a complex recursive function that will return a Code Quotation/Expression itself.

实际上,我的要求是, exprFun 能够访问/操纵这些变量的代code报价为lambda函数的RHS的一部分的产生。

Effectively, my requirement is that exprFun be able to access/manipulate these variables as part of the generation of the Code Quotation for the rhs of the lambda function being generated.

推荐答案

如果你想想看,关于逃离范围的错误完全是有道理的:什么样的情况下,如果你记住这些变量,然后将他们没有任何意义(即超出其范围)?编译器不能保证正确的方式。你应该不是真的被允许与这些变量这样的。

If you think about it, the error about "escaping scope" totally makes sense: what if you "remember" these variables and then insert them in a context that doesn't make sense (i.e. out of their scope)? The compiler can't guarantee correctness that way. You shouldn't really be allowed to work with these variables that way.

你可以做的却是让 exprFun 管理​​其自己的变量,并返回 Expr的&LT;内部 - &GT;内部 - &GT; INT&GT; ,而不是仅仅 Expr的&LT; INT&GT;

What you can do instead is make exprFun manage its own variables and return Expr<int-> int-> int> instead of just Expr<int>:

let exprFun = <@ fun a b -> a + b @>
let q1 = <@ fun x y -> (%exprFun) x y @>

当然,由此产生的前pression不会完全等同于你希望得到什么。即,代替这样的:

Of course, the resulting expression won't be exactly equivalent to what you're expecting to get. That is, instead of this:

fun x y -> x + y

您会得到这样的:

fun x y -> (fun a b -> a + b) x y

但是,这等同的逻辑的,所以不应该是什么像样的报价消费的问题。

But this is equivalent logically, and so shouldn't be a problem for any decent quotation consumer.

另外,如果你真的坚持拼接使用参数动态生成的报价,你可以使用一个存根函数调用,然后重写报价作为一个单独的步骤:

Alternatively, if you really insist on splicing a quotation dynamically generated using arguments, you can use a stub function call and then rewrite the quotation as a separate step:

let exprStub (a: int) (b: int): int = failWith "Don't call me!"
let exprFun (a:Expr) (b:Expr) -> <@@ %%a + %%b @@>
let rec rewrite (e: Expr<_>): Expr<_> = 
    match e with
    ...
    | SpecificCall <@exprStub@> (_, _, [a;b]) ->
          exprFun a b
    ...

let q1' = <@ fun x y -> exprStub x y @>
let q1 = rewrite q1'

这篇关于code语录:如何获取的lambda函数内部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆