HaskellでLispを書く日記 このページをアンテナに追加 RSSフィード

2007-03-06

evalの作成(if編) evalの作成(if編) - HaskellでLispを書く日記 を含むブックマーク はてなブックマーク - evalの作成(if編) - HaskellでLispを書く日記 evalの作成(if編) - HaskellでLispを書く日記 のブックマークコメント

なんとなくifが出来ると言語っぽい処理をしている気がしてくるので、今回はifを作ることにする。

ifは(if p t e)と3つの引数をとり、pの評価結果が真のとき(#tをはじめとして#f以外の全ての値)にt(thenのつもり)を評価して返し、pの評価結果が偽のとき(#fのときのみ)にe(elseのつもり)を評価して返す。

真偽値の登録

今回作っているlispは一応scheme系を自称しているので真偽値は#t/#fで表すことにする。パース結果としての#t/#fを評価したときに評価結果としても#t/#fとなってほしいので、#tと#fを環境に登録する。

env = read "((x . a) (y . b) (#t . #t) (#f . #f))"

Eqクラスインスタンス

最終的にifの内部処理ではSexp型の値としての#f(=Symbol "#f")との比較をすることになるので、Sexp型自体で同値判定(==)の演算が出来るようにEqクラスインスタンスとする。

deriving宣言を使ってみたらうまく動いているようなので今回はこれを使って楽をする。

data Sexp = Nil | Symbol String | Cons Sexp Sexp deriving Eq

if用eval部分

ifの処理をするのは、4つの要素をもつリストであり最初の要素がifになっている場合のとき。なので、4段階にConsされたものにおいて、順番に(Symbol "if")、p、t、eにパターンマッチさせる。そしてマッチしたならば、pについてevalし、その結果がSymbol "#f"と等しくなかった場合はtについてevalし、等しい場合はeについてevalする。

eval (Cons (Symbol "if") (Cons p (Cons t (Cons e _)))) env = if eval p env /= Symbol "#f" then eval t env else eval e env

テスト

ifの処理をテストしてみる。とはいっても、まだ真偽値を返す関数を1つも持っていないので、寂しいけど定数をあたえてテストする。

真を表す#tのときは、xを評価したaを返す。偽を表す#fのときはyを評価したbを返す。

他の値でも試してみる。()、'foo等も#fではないので真の扱いになりx側を評価する。

最後にifの入れ子を試してみる。

Main> eval (read "(if #t x y)") env
a
Main> eval (read "(if #f x y)") env
b
Main> eval (read "(if () x y)") env
a
Main> eval (read "(if 'foo x y)") env
a
Main> eval (read "(if (if #t #f #t) x y)") env
b
トラックバック - http://haskell.g.hatena.ne.jp/haskelisp/20070306