Haskell: Pugs 6.0.2の評価関数に関するメモ
自分用のメモなので、何をやっているのか気にしないで下さいw。
Pugs 6.0.0におけるレクサとパーサの動作は、大よそわかった。
問題はパーサが出力したASTをevalするやり方。
Pugs 6.0.2から変数とサブルーチンがサポートされた。それによってsrc/Eval.hsに新たにEnv型が用意された。「環境」を表現するためにあるようだ。環境の概念については、岩波講座 ソフトウェア科学 4 プログラミング言語 が参考になる。*1
環境の中に存在するシンボル(sym)の読み込みと上書きをするコードをPugs 6.0.2(リビジョン7)をベースにして書いてみた。以下がそのコード。コードの1行目に「{-# OPTIONS -fglasgow-exts #-}」というプラグマを書いておかないといけないみたい。
% vim symbol.hs {-# OPTIONS -fglasgow-exts #-} import Debug.Trace type VInt = Integer type VStr = String type Var = String data Val = VInt VInt | VStr VStr | VError VStr Exp deriving (Show, Eq, Ord) data Exp = Syn String [Exp] | Var Var | Val Val deriving (Show, Eq, Ord) type Symbol = (String, Val) type Symbols = [Symbol] -- data Env = Env { sym :: Symbols } deriving (Show) emptyEnv = Env { sym = initSyms } initSyms :: Symbols initSyms = [("foo", VInt 1), ("greeting", VStr "hello")] -- addSym :: Env -> [(String, Val)] -> Env addSym env [] = env addSym env ((var, val):vs) = env{ sym = (var, val):(sym $ addSym env vs) } retVal :: Val -> ((Env -> Env), Exp) retVal val = (id, Val val) reduce :: Env -> Exp -> ((Env -> Env), Exp) reduce env@Env{ sym = sym } exp@(Var var) | Just val <- lookup var sym = retVal val reduce env exp@(Syn name exps) | name == "=" , [Var var, exp] <- exps , trace ("exp = " ++ show exp) True , (fenv, Val val) <- reduce env exp , trace ("var = " ++ show var ++ ", val = " ++ show val) True = (combineEnv fenv var val, Val val) where combineEnv f var val env = (f env) `addSym` [(var, val)] reduce env other = (id, other) -- evaluate :: Env -> Exp -> Val evaluate env exp | Val v <- val = v | otherwise = VError "Invalid expression" exp where (env', val) = reduce env exp
ghciで実行すると、以下のようになる。
最初の2つの実行例は、環境の中のシンボルの中にある変数fooと変数greetingからそれらの値を取り出せるかどうか試している。最後の例は、環境の中のシンボルの中にある変数fooの値を更新できるかどうか試している。
evaluate関数の第1引数には、初期の環境を渡している。第2引数にはExp型のASTを渡している。
% ghci symbol.hs *Main> evaluate emptyEnv (Var "foo") VInt 1 *Main> evaluate emptyEnv (Var "greeting") VStr "hello" *Main> evaluate emptyEnv (Syn "=" [Var "foo", Val(VInt 2)]) exp = Val (VInt 2) var = "foo", val = VInt 2 VInt 2
感想。
パーサでASTを出力する処理も難しいけれども、ASTをevalする処理の方がもっと難しいと思った。初期リリースのPugsのコードが少しずつ読めるようになってきたので、引き続き頑張ろうと思う。
それにしても、Pugsの進化は凄まじい。バージョンが0.02上がっただけでも、コードを理解するのが凄く大変w。
- 作者: 武市正人
- 出版社/メーカー: 岩波書店
- 発売日: 1994/06/17
- メディア: 大型本
- この商品を含むブログ (2件) を見る