= Scheme課題memo =
Guileだとスタックトレースが見易くて便利らしいけれど、gaucheでもとりあえずは(print '''hoge''')でprintfデバッグすると十分に便利。
== この課題で(多分)よく使うemacsショートカット ==
* C-x 2で画面分割
* C-x oで別の画面に移動
* (setq scheme-program-name "gosh")を設定ファイルに書くとか、どっか適当なところに書いてから最後の)にカーソルを合わせてC-x C-eでscheme処理系モードの設定完了。C-x C-eはscheme処理系モードがある時はelisp式じゃなくてscheme式として評価しようとするみたいなのでrun-scheme前にした方がいいかも。
* M-x run-schemeでスキーム走らせる。
* scheme処理系モードでC-c C-lでファイルの読み込み
== インタプリタ課題 ==
とりあえず課題ページの例が動くところまで、ほとんど課題ページの内容をコピペです。ちょこちょこ改訂されてるので一度コピペしなおしてみると便利かも。
自分で書く部分は、
*make-top-env内のdefine-var!の羅列の中で<,>等を追加
*base-apply内で*lambda*を見つけた場合の処理
*def-eval
*if-eval
*quote-eval
の五つくらいです。
よって根幹部分はこんな風になります。上にないfoo-evalは課題ページのもので確かOK。beginも簡単だけど、例では使ってないので省略。システムテストも通っちゃう。
{{{#!scheme
(cond ((eof-object? exp) '*exit*)
((boolean? exp) exp)
((number? exp) exp)
((string? exp) exp)
((symbol? exp) (var-eval exp env))
((null? exp) exp)
((not (list? exp)) (eval-error 'syntax-error exp))
((equal? (car exp) 'exit) '*exit*)
;; ((equal? (car exp) 'begin (begin-eval exp env))
((equal? (car exp) 'lambda) (lambda-eval exp env))
((equal? (car exp) 'let) (let-eval exp env))
((equal? (car exp) 'define) (def-eval exp env))
;; ((equal? (car exp) 'letrec)
((equal? (car exp) 'if) (if-eval exp env))
((equal? (car exp) 'quote) (quote-eval exp env))
(#t (app-eval exp env))))
}}}
make-top-env内のdefine-var!の羅列については課題ページ中の他のprimitive行を見て真似すればいいので省略。
if-evalについて。<
>
これも標準のifを使うだけ、なのですが、環境とかその辺を考慮してあげないといけないので評価はbase-evalを使います。標準のifを使うのは手抜きっぽい? どうするにせよ評価しない式がある以上、特殊形式は必要だろうから別に恥ずかしい事じゃないよ!
{{{
(if (base-eval '''expの該当部分''' env)
(base-eval '''expの該当部分''' env)
(base-eval '''expの該当部分''' env))
}}}
def-evalについて。<
>
環境の拡張だから前の課題のdefine-var!一発だね! base-evalしてあげることを忘れずにね!
quote-evalについて。<
>
といってもexp、つまり入力のリスト(quote '''hoge''')から必要部分を返すだけなので、
{{{
(car (cdr exp))
}}}
で。特に難しいところなし。
base-applyで*lambda*をみつけた時の処理について<
>
たぶん課題の真打ちがこれ。とりあえず俺俺処理系に渡されたリストは課題ページのapp-evalによっていい感じにリストの深い中身が評価されてから、base-applyにfun,args,envが渡ってくるはずです。詳しくは[[http://practical-scheme.net/gauche/man/gauche-refj_76.html#index-map-1]]とか[[http://practical-scheme.net/gauche/man/gauche-refj_27.html#index-let_002a]]とか。たぶん本当はこういうリファレンス読んで理解する事込みの課題なんでしょうが、とりあえずprintデバッグでトライアンドエラーでもわかったりします。<
>
fun,argsの中身は中身評価後のcarとcdrで、funはlambda-evalで決めた通り(*lambda* lambda評価時のenv (変数リスト) lambdaの中身)の形をしてかえってくるはずで、argsが残りの部分のリストです。<
>
さて、ここまで落ちつけば、ここでするべきは
1. ''変数リスト''にあるシンボルに''args''をその順であてはめる。つまり、''lambda評価時のenv''を''lambdaの変数''と''args''で拡張する。
1. 先の課題のextend-envに渡せるリストを、''変数リスト''と''lambdaの中身''を操作して作る。
2. extend-envしてnewenvを作る
1. ''lambdaの中身''をnewenvの元で評価させる
だとわかります。1.1が一見すると''lambdaの変数''と''args''二つのリストを同時に扱わないといけないので面倒そうですが、「lambdaの中など、複数の式を書いてよい部分に1つの式しか書いてはいけないという制約を設けてもよい。」らしいのでくっつけたリスト作るだけで終わり。(複数の変数を受けつけるようにしても「構文エラーへの対応は無視」とかを拡大解釈して片一方のリストで回せば初めの方の課題と同レベル。) ということで、base-applyも実は楽ちんです。
直接答え書くのは控えたけれど、初めの方の課題レベルまでは簡単になったと思うので後は頑張ってね。役にたったと思ったら[[集合と位相]]でおかえししてくれればいいよ。
----
[[Category読み物]]