Schemeをつくろう(17) eval
なんだかんだ色々迷走しながらも、なんとかここまでまとまりました。lambdaが大体出来上がってきました。出来ることといえば、lambda位なんですが、クロージャらしきモノもあります。
ポイントとか
- evalの基本はeval(オブジェクト, 環境)で評価します。
- 変数のつくりかた
- マイ関数のつくりかた
- 簡単。「lambda」ってあったら、
- closure(束縛用引数(x y), 関数の中身, 今の環境のコピー)
- 何もしないで、保存。それだけ。
- ただ、環境はポインタになってるので、リストの先頭アドレスのコピーを取っておく事が重要。コピーじゃないとダメぇ。
- マイ関数を呼び出す
- undefについて。
- どうもnullだけだとマズイようだ。値に何も入ってないことを示すのに、nullだけでは判断が付かない。つまり、(define nil '())が出来ない。適当なアドレスをundefに割り振ることにした。
- applyがいったい何者なのかイマイチわかってない。
- ((について。
- ((ってあったら、とりあえず中を見てみる。
gosh> ((+ 1 2 3) (+ 4 5 6)) *** ERROR: invalid application: (6 15)
-
- エラーは色々ヒントを教えてくれる。素晴らしい。
作ってみてわかったことは「eval重要」ってこと。evalが違うと、Common Lispになったり、Schemeになっちゃったりする。だからスゲーeval重要。
ソース
今の所のソース。ソースは長いのか。短めか。270行位。
作れば作る程短くなってしまう不思議。
#include <stdio.h> #include "error.h" #include "list.h" #include "symbol.h" #include "eval.h" static object s_define, s_lambda, s_if, s_apply, s_quote, s_eval, s_env; /* eval */ static object eval_map(object o, object *env); static object eval_value(object sym, object *env); static object eval_symbol(object sym, object args, object *env); static object apply(object sym, object args); static object apply_closure(object c, object values); /* syntax */ static object if_syntax(object args, object *env); static object apply_syntax(object args, object *env); static object eval_syntax(object args, object *env); static object lambda(object args, object *env); /* define */ static object define(object args, object *env); static void append_env(object sym, object value, object *env); static object find_value(object sym, object *env); static object assq(object key, object list); object eval(object o, object *env) { if (is_null(o)) /* () -> error */ error("eval : null"); else if (is_symbol(o)) /* abc -> "hello!!" */ return eval_value(o, env); else if (!is_pair(o)) /* 123 -> 123 */ return o; else { object head = car(o); object body = cdr(o); if (is_symbol(head)) /* (+ 1 2) -> 3 */ return eval_symbol(head, body, env); else if (is_closure(head)) /* (<closure> body) */ return apply_closure(head, body); else if (is_pair(head)) /* ((lambda ..) (.. -> (<closure> .. */ return eval(eval_map(o,env), env); else error("eval : can't eval"); } } /* eval all aruguments ((+ 1 2 3) ...) -> (6 ...) */ static object eval_map(object args, object *env) { if (is_null(args)) return null(); else if (is_pair(args)) { object a,d; a = eval(car(args), env); /* eval */ d = eval_map(cdr(args), env); /* next */ return cons(a, d); } else return eval(args, env); /* error かも。 */ } static object eval_value(object sym, object *env) { object value = find_value(sym, env); if (!is_undef(value)) return value; else error("eval : undefind value"); } static object eval_symbol(object sym, object args, object *env) { object value = find_value(sym, env); if (!is_undef(value)) { args = eval_map(args, env); return apply(value, args); } if (eq_symbol(sym, s_define)) return define(args, env); else if (eq_symbol(sym, s_apply)) return apply_syntax(args, env); else if (eq_symbol(sym, s_eval)) return eval_syntax(args, env); else if (eq_symbol(sym, s_lambda)) return lambda(args, env); else if (eq_symbol(sym, s_if)) return if_syntax(args, env); else if (eq_symbol(sym, s_quote)) return car(args); else if (eq_symbol(sym, s_env)) { /* debug syntax */ display(*env); newline(); return undef(); } else error("eval : undefind"); } /* bind aruguments */ static object apply(object fun, object args) { if (is_function(fun)) return call(fun, args); else if (is_closure(fun)) return apply_closure(fun, args); else error("apply error"); } static object apply_closure(object c, object values) { object args = closure_args(c); object body = closure_body(c); object root = closure_env(c); object res = undef(); object *env = &root; /* bind */ if (!is_pair(args)) /* (lambda x x) */ append_env(args, values, env); else { for (; !(is_null(args) || is_null(values)); args = cdr(args), values = cdr(values)) append_env(car(args), car(values), env); if (!(is_null(args) && is_null(values))) error("closure : bind error"); } /* eval body */ for (; !is_null(body); body = cdr(body)) res = eval(car(body), env); return res; } /* syntax */ static object lambda(object args, object *env) { if (length(args) >= 2) return closure(car(args), cdr(args), *env); else error("lambda : arugument error"); } static object apply_syntax(object args, object *env) { if (length(args) == 2) { object sym = car(args); object fun; fun = find_value(sym, env); if (is_undef(fun)) error("syntax apply : not find value"); args = eval(cadr(args), env); return apply(fun, args); } else error("syntax apply : arugument error"); } static object eval_syntax(object args, object *env) { if (length(args) == 1) return eval(eval(car(args), env), env); else error("syntax eval : arugument error"); } static object if_syntax(object args, object *env) { if (length(args) == 3) { object ex = car(args); ex = eval(ex, env); if (!is_boolean(ex)) error("syntax if : not boolean"); if (is_true(ex)) return eval(cadr(args), env); else return eval(car(cddr(args)), env); } else error("syntax if : arugument error"); } /* define */ static object define(object args, object *env) { object sym, value, head, body; if (!is_pair(args)) error("define : argument error"); head = car(args); body = cdr(args); if (is_pair(head)) { /* closure */ sym = car(head); value = closure(cdr(head), body, *env); } else if (is_symbol(head)) { /* value */ sym = head; if (length(body) != 1) error("define argument error"); value = eval(car(body), env); } else error("define : not symbol"); /* set values */ if (is_null(*env)) /* global */ set_symbol_value(sym, value); else /* local */ append_env(sym, value, env); return value; } static void append_env(object sym, object value, object *env) { *env = cons(cons(sym, value), *env); } static object find_value(object sym, object *env) { /* local */ object value; if (!is_null(value = assq(sym, *env))) return cdr(value); /* global */ if (!is_undef(value = get_symbol_value(sym))) return value; /* not find */ return undef(); } /* util */ static object assq(object key, object list) { while (!is_null(list)) { if (eq_symbol(car(car(list)), key)) return car(list); list = cdr(list); } return null(); /* not find */ } void init_syntax_symbols(void) { s_define = symbol("define"); s_lambda = symbol("lambda"); s_if = symbol("if"); s_apply = symbol("apply"); s_quote = symbol("quote"); s_eval = symbol("eval"); s_env = symbol("env"); }
修行が足りません。修行じゃぁ〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜。