2011-06-20 121 views
8

今天早些时候,我遇到了F#报价的限制,并在这里问了一个问题吧:现在F# quotations: variable may escape scopeF#报价的另一个限制?

,将在http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf从出现到MetaOcaml F#的例子时,我可能会遇到的另一个限制。

这一次,我这个MetaOcaml片段:

let rec peval2 p env fenv= 
    match p with 
    Program ([],e) -> eval2 e env fenv 
    | Program (Declaration (s1,s2,e1)::tl,e) -> 
     .<let rec f x = .~(eval2 e1 (ext env s2 .<x>.) 
            (ext fenv s1 .<f>.)) 
      in .~(peval2 (Program(tl,e)) env (ext fenv s1 .<f>.))>. 

,我又把它转换成

let rec peval2 p env fenv = 
    match p with 
    | Program ([], e) -> eval2 e env fenv 
    | Program (Declaration (s1, s2, e1) :: tl, e) -> 
     <@ let rec f x = %(eval2 e1 (ext env s2 <@ x @>) 
            (ext fenv s1 <@ f @>)) 
      in %(peval2 (Program(tl, e)) env (ext fenv s1 <@ f @>)) @> 

我得到以下编译时错误:This expression was expected to have type int -> Expr<int> but here has type Expr<'a>与两个<@ f @>

直觉上,我认为这个错误很有意义。但是在这种情况下,F#中有没有一种方法来描述我想要的内容?

代码示例:

open Microsoft.FSharp.Quotations 

type Exp = 
    | Int of int 
    | Var of string 
    | App of string * Exp 
    | Add of Exp * Exp 
    | Sub of Exp * Exp 
    | Mul of Exp * Exp 
    | Div of Exp * Exp 
    | Ifz of Exp * Exp * Exp 

type Def = Declaration of string * string * Exp 
type Prog = Program of Def list * Exp 

exception Yikes 

let env0 = fun x -> raise Yikes 

let fenv0 = env0 

let ext env x v = fun y -> if x = y then v else env y 

let rec eval2 e env fenv = 
    match e with 
    | Int i -> <@ i @> 
    | Var s -> env s 
    | App (s, e2) -> <@ %(fenv s) %(eval2 e2 env fenv) @> 
    | Add (e1, e2) -> <@ %(eval2 e1 env fenv) + %(eval2 e2 env fenv) @> 
    | Sub (e1, e2) -> <@ %(eval2 e1 env fenv) - %(eval2 e2 env fenv) @> 
    | Mul (e1, e2) -> <@ %(eval2 e1 env fenv) * %(eval2 e2 env fenv) @> 
    | Div (e1, e2) -> <@ %(eval2 e1 env fenv)/%(eval2 e2 env fenv) @> 
    | Ifz (e1, e2, e3) -> <@ if %(eval2 e1 env fenv) = 0 
          then %(eval2 e2 env fenv) 
          else %(eval2 e3 env fenv) @> 

let rec peval2 p env fenv = 
    match p with 
    | Program ([], e) -> eval2 e env fenv 
    | Program (Declaration (s1, s2, e1) :: tl, e) -> 
     <@ let rec f x = %(eval2 e1 (ext env s2 <@ x @>) 
            (ext fenv s1 <@ f @>)) 
      in %(peval2 (Program(tl, e)) env (ext fenv s1 <@ f @>)) @> 

回答

4

我想你打同样的问题,因为在上一个问题 - 当我从文件复制必要的声明,我得到:

error FS0446: The variable 'f' is bound in a quotation but is used as part of a spliced expression. This is not permitted since it may escape its scope.

这很有意义 - 在F#中不允许捕获在拼接表达式中绑定在引号中的变量,这在代码段中是明确的。

我不完全确定你为什么会得到一个不同的错误消息 - 如果你可以发布一个最小的完整样本,那么可以回答,但你仍然会打这个变量捕获限制。 (这可能是MetaOCaml中使用相当多的东西)。

+0

好的:/我发布了一个代码示例,它产生了我正在谈论的错误。但是,如果我从eval2删除了几行代码,则会得到与另一个问题相同的错误:/ –