2

I have doubts about some topics. In short I have to write an interpreter in Ocaml both static and dynamic scope. For now I implemented a version with static scoping through the use of an environment (IDE * value) lists, and a eval (evn * exp), passing evn when a statement.

The question then, and 'can be developed both scoping (dynamic - static) with a list and a eval function like this, by making changes to the reading of the list or you have to take another way?

Here a part of code:

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

The evaluation code:

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")) 

Here 's an example of me making a statement:

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)))))));;

Or

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

With these examples the result is Int 1. In my book this example gives:

Lexical : Int 1

Dynamic : Int 2

Its looks a correct implementation.

Jilz
  • 31
  • 5
  • 1
    You can keep using the env list even in dynamic scoping. If you have done static scoping correctly, then dynamic scoping can be implemented easily as a "bug", throwing away the environments from your closures. – camlspotter May 26 '16 at 02:00
  • camlspotter's comment is an actual answer, nevertheless you should put in some minimal OCaml code so we could provide a bit more concrete answers – Anton Trunov May 26 '16 at 06:58

1 Answers1

2

All you need to do is replace

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

with

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

At that point, you can also remove the env component from Closure, because it's never used.

FWIW, I kept your variable naming in the above code, though it is really weird, given that funct is the parameter name, and args is the function body.

Andreas Rossberg
  • 34,518
  • 3
  • 61
  • 72
  • "*...you can also remove the env component from `Closure`...*", i.e. we can ditch `Clojure` altogether, because in this case `Fun` and `Closure` are the same thing. – Anton Trunov May 26 '16 at 12:27