2016-05-25 8 views
2

私はいくつかの話題について疑問を抱いています。つまり、Ocamlには静的スコープと動的スコープの両方のインタープリタを記述する必要があります。 今のところ私は、環境(IDE *値)リストとeval(evn * exp)を使用して静的スコープを持つバージョンを実装し、ステートメントのときにevnを渡しました。OCamlレキシカル対ダイナミックスコープ

質問は、リストの読み方を変更することによって、リストとそのような評価関数の両方をスコープ(動的 - 静的)とするか、別の方法をとる必要がありますか?ここで

コードの一部:

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 です:

字句:のInt 1

ダイナミックます。int 2つの

その正しい 実装を探します。

+1

ダイナミックスコープでもenvリストを使用できます。静的スコープを正しく行っていれば、動的スコープを「バグ」として簡単に実装して、クロージャから環境を取り除くことができます。 – camlspotter

+0

camlspotterのコメントは実際の回答ですが、OCamlの最小限のコードを入れてください。より具体的な回答を –

答えて

2

それが使用されることはないですので、あなたがする必要があるのは、その時点で

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

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

を交換されて、あなたはまた、閉鎖からenvコンポーネントを削除することができます。

FWIW、変数名は上記のコードに入れましたが、functはパラメータ名、argsは関数本体です。

+0

"* ...あなたは' Closure' ... * "からenvコンポーネントを削除することもできます。この場合、「楽しい」と「閉じた」というのは同じことなので、私たちは 'Clojure'を完全に捨てることができます。 –

関連する問題