【问题标题】:OCaml lexical vs dynamic scopingOCaml 词法与动态作用域
【发布时间】:2016-09-23 16:54:06
【问题描述】:

我对一些话题有疑问。简而言之,我必须在 Ocaml 中编写静态和动态范围的解释器。 现在,我通过使用环境(IDE * 值)列表和 eval(evn * exp)实现了一个具有静态范围的版本,并在语句中传递了 evn。

然后的问题是,' 可以通过更改列表的读取方式来开发具有列表和 eval 函数的范围(动态 - 静态),或者您必须采取其他方式?

这里是部分代码:

type ide = string

type bi_operator = 
     Plus
    |Minus
    |Mul
    |Div
    |Eq
    |LThan
    |LEq
    |And
    |Or

type exp =   
    Var of ide
    |Const of value
    |Fun of ide * exp
    |Not of exp    
    |BOp of exp * bi_operator * exp
    |Let of ide * exp * exp
    |If of exp * exp * exp    
    |FunApp of exp * exp           



and value =  
| Int of int    
| Bool of bool          
| Closure of env * string * exp 
and env = (ide * value) list

评估代码:

let rec eval (evn,e) = match e with
  | Const _ -> expToV(e) 
  | Var x -> lookup (x,evn)
  | BOp (a,b,c) -> ( match ((eval(evn,a)),(eval(evn,c))) with
    | (Int a, Int c) -> 
        ( match b with
          | Plus -> Int (a + c)
          | Minus -> Int (a - c)
          | Mul -> Int (a * c)
          | Div -> Int (a / c)  

          | Eq  -> Bool (a = c)                                                                                     
          | LThan  -> Bool (a < c)
          | LEq  -> Bool (a <= c)
          | _   -> raise (MLFailure "Not a valid Int operator")
        )

    | (Bool a, Bool c) ->
        ( match b with
          | Eq  -> Bool (a = c)
          | And -> Bool (a && c)
          | Or  -> Bool (a || c)
          | _   -> raise (MLFailure "Not a valid Bool operator")
        )
    | _ -> raise (MLFailure "Bin arguments do not match"))


  | Fun (a,b) -> Closure (evn,a,b)

  | Not (a) -> (match (eval(evn,a)) with
    | (Bool a) -> if(a = false) then Bool(true) else Bool(false)
    | _ -> raise (MLFailure "Bin arguments do not match"))

  | Let (a,b,c) -> eval ( ((a,eval (evn,b))::evn) , c)

  | If (a,b,c) -> if (eval (evn,a) = (Bool true)) then (eval (evn,b)) else (eval (evn,c))  

  | FunApp (a,b) -> (match eval (evn,a) with
                 | Closure (environment,funct,args) ->  eval (((funct, eval (evn,b))::environment),args)
                 | _ -> raise (MLFailure "Bin arguments do not match")) 

这是我发表声明的一个例子:

let _ = eval ([("x", Int 3);("t", Int 5);("z", Int 5);("x", Int 5);("y", Int 1)], (Let ("x", Const (Int 1),
                    Let ("f", Fun ("y", Var "x"),
                      Let ("x", Const (Int 2), FunApp (Var "f", Const(Int 0)))))));;

或者

let _ = eval ([], (Let ("x", Const (Int 1),
                    Let ("f", Fun ("y", Var "x"),
                      Let ("x", Const (Int 2), FunApp (Var "f", Const(Int 0)))))));;

通过这些示例,结果是 Int 1。 在我的书中,这个例子给出了:

词法:整数 1

动态:Int 2

它看起来是正确的 执行。

【问题讨论】:

  • 即使在动态范围内,您也可以继续使用 env 列表。如果你正确地完成了静态作用域,那么动态作用域可以很容易地实现为一个“错误”,从你的闭包中丢弃环境。
  • camlspotter 的评论是一个实际的答案,但是您应该输入一些最小的 OCaml 代码,以便我们可以提供更具体的答案

标签: dynamic scope ocaml lexical-scope lexical-closures


【解决方案1】:

你需要做的就是替换

| Closure (environment,funct,args) ->  eval ((funct, eval (evn,b))::environment,args)

| Closure (environment,funct,args) ->  eval ((funct, eval (evn,b))::evn,args)

此时,您还可以从 Closure 中删除 env 组件,因为它从未使用过。

FWIW,我在上面的代码中保留了你的变量命名,虽然这真的很奇怪,因为funct 是参数名称,args 是函数体。

【讨论】:

  • "...您也可以从Closure..." 中删除 env 组件,即我们可以完全放弃Clojure,因为在这种情况下@987654328 @ 和 Closure 是同一个东西。
猜你喜欢
  • 2013-11-03
  • 2014-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 2013-11-06
  • 2012-05-02
相关资源
最近更新 更多