首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F#引号:变量可以转义范围

F#引号:变量可以转义范围
EN

Stack Overflow用户
提问于 2011-06-20 16:06:24
回答 1查看 698关注 0票数 5

我有一个代码:

代码语言:javascript
复制
let rec h n z = if n = 0 then z
                else <@ (fun x -> %(h (n - 1) <@ x + %z @>)) n @>

从MetaOcaml示例转换而成的http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf示例

在本文中,说明了上面的示例将得到参数3.<1>. (以MetaOcaml符号表示)的如下结果:

代码语言:javascript
复制
.<(fun x_1 -> (fun x_2 -> (fun x_3 -> x_3 + (x_2 + (x_1 + 1))) 1) 2) 3>.

如您所见,xx_1x_2等所取代,因为否则x只会引用最内部的fun中的x

但在F#,这是不允许的。我得到编译时错误:“变量'x‘被绑定在一个引号中,但是用作一个拼接表达式的一部分。这是不允许的,因为它可能会脱离它的作用域。”因此,问题是:如何才能改变这种情况,使其能够编译并具有与MetaOcaml输出相同的语义?

更新到注释:我使用PowerPack实际评估报价。但我不认为这与它有任何关系,因为错误发生在编译时。到目前为止,QuotationEvaluation还能工作。然而,我知道这可能不是最有效的实施。

更新到Tomas的答案:我真的不希望x是全局的,或者逃避作用域。但我想要的是相当于

代码语言:javascript
复制
let rec h n z = if n = 0 then z
                else (fun x -> (h (n - 1) (x + z))) n

加上引文。您的答案给出了(h 3 <@ 1 @>).Eval() = 4,上面的结果是h 3 1 = 7。在这里,我希望7是答案。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-06-20 16:29:49

F#引号语法不支持可能逃避作用域的变量,因此需要使用Expr操作显式地构造树。像这样的事情应该能起作用:

代码语言:javascript
复制
open Microsoft.FSharp.Quotations

let rec h n (z:Expr<int>) = 
  if n = 0 then z                
  else 
    let v = new Var("x", typeof<int>)
    let ve = Expr.Var(v)
    Expr.Cast<int>
        (Expr.Application( Expr.Lambda(v, h (n - 1) <@ %%ve + %z @>), 
                           Expr.Value(n)))

但是,这是一个非常人工的例子(演示在MetaOCaml中捕获变量,这在F#中是不可用的)。它只生成类似于(2 + (1 + ...))的表达式。通过编写这样的东西,您可以得到相同的结果:

代码语言:javascript
复制
let rec h n (z:Expr<int>) = 
  if n = 0 then z                
  else h (n - 1) <@ n + %z @>

甚至更好:

代码语言:javascript
复制
[ 1 .. 4 ] |> List.fold (fun st n -> <@ n + %st @>) <@ 0 @>

我也克服了F#报价中的这一限制,如果这得到支持,那就太好了。但是,我认为这在实践中并不是一个大问题,因为F#引用并不用于分阶段的元编程。它们在分析现有F#代码时比生成代码更有用。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6414185

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档