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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.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
F#QUOTES:变量可能会逃逸范围_F#_Metaprogramming_Multi Stage Programming_Metaocaml - Fatal编程技术网

F#QUOTES:变量可能会逃逸范围

F#QUOTES:变量可能会逃逸范围,f#,metaprogramming,multi-stage-programming,metaocaml,F#,Metaprogramming,Multi Stage Programming,Metaocaml,我有一段代码: let rec h n z = if n = 0 then z else <@ (fun x -> %(h (n - 1) <@ x + %z @>)) n @> 正如您所看到的,x's被x_1,x_2等所取代。因为x否则只会引用最里面的x 但在F#中,这是不允许的。我得到了编译时错误:“变量‘x’被绑定在引号中,但被用作拼接表达式的一部分。这是不允许的,因为它可能会超出其范围。”因此问题是:如何更改它,使其能够编译

我有一段代码:

let rec h n z = if n = 0 then z
                else <@ (fun x -> %(h (n - 1) <@ x + %z @>)) n @>
正如您所看到的,
x
's被
x_1
x_2
等所取代。因为
x
否则只会引用最里面的
x

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

更新评论:我使用PowerPack来实际评估报价。但我认为这与此无关,因为错误发生在编译时。到目前为止,报价评估是有效的。然而,我知道这可能不是最有效的实施

更新Tomas的答案: 我真的不希望
x
是全局的,或是逃避范围。但我想要的是等同于

let rec h n z = if n = 0 then z
                else (fun x -> (h (n - 1) (x + z))) n
有引文。您的答案为
(h3).Eval()=4
,其中上述结果为
h3 1=7
。这里,我希望
7
是答案。

F#引号语法不支持可能超出范围的变量,因此需要使用
Expr
操作显式构造树。像这样的事情应该可以做到:

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)))
或者更好:

[ 1 .. 4 ] |> List.fold (fun st n -> <@ n + %st @>) <@ 0 @>
[1..4]|>List.fold(fun st n->)

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

我不知道MeyaOCaml,但似乎您试图在实际F#代码中使用引号lambda中的变量。引用不是真正的F代码,因此你也不能对它们进行评估(除了LINQ evaluator,它并不完美)。你看起来像个称职的人:),但这并不完全是我想要的。我的问题可能不够清楚,因此问题将在2秒内更新。@LasseSpeholt:我将版本更改为使用
new Var
,而不是
Var.Global
(这是错误的)。现在应该在每次迭代中声明一个新变量(它们将具有相同的名称,但将是不同的变量)。@Tomas Thank:)按预期工作。然而,我想我会回到MetaOcaml上来,因为我想将它用于多阶段编程。@lasseSpeholt-MetaOcaml在这方面肯定更好。顺便说一句:我很想知道你的情况是什么(只是为了更好地了解多阶段编程的实际用途)。@Tomas我已经看了几个方面,因为我想在夏天找到一个项目。多阶段编程似乎很有趣,因为其中一个目标是提高抽象性,而不会造成高性能的损失。在许多较新的语言中,我们都有抽象,您最终必须进行分解,才能在高性能应用程序中获得适当的性能。(再一次,我知道——基于另一个所谓的问题——F#PowerPack Eval的性能不好)
let rec h n (z:Expr<int>) = 
  if n = 0 then z                
  else h (n - 1) <@ n + %z @>
[ 1 .. 4 ] |> List.fold (fun st n -> <@ n + %st @>) <@ 0 @>