1と13のリビジョン間の差分 (その間の編集: 12回)
2011-02-07 01:20:19時点のリビジョン1
サイズ: 2708
編集者: Naoaki Iwakiri
コメント:
2011-02-07 02:52:36時点のリビジョン13
サイズ: 3755
編集者: Naoaki Iwakiri
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 1: 行 1:
Naoaki Iwakiri/Scheme課題memo Guileだとスタックトレースが見易くて便利らしいけれど、gaucheでもとりあえずは(print '''hoge''')でprintfデバッグすると十分に便利。
行 3: 行 3:







とりあえず課題ページの例が動くところまで、ほとんど課題ページの内容をコピペです。ちょこちょこ改訂されてるので一度コピペしなおしてみると便利かも。
自分で書く部分は、
 *make-top-env内のdefine-var!の羅列の中で<,>等を追加
 *base-apply内で*lambda*を見つけた場合の処理
 *def-eval
 *if-eval
 *quote-eval
の五つくらいです。
よって根幹部分はこんな風になります。上にないfoo-evalは課題ページのもので確かOK。beginも簡単だけど、例では使ってないので省略。システムテストも通っちゃう。
行 4: 行 20:
(define (base-eval exp env)
  (define (var-eval exp env)
    (cdr (lookup-var exp env)))
  (define (lambda-eval exp env)
    (if (pair? (cdr exp))
 (cons '*lambda* (cons env (cdr exp)))
 (eval-error 'syntax-error exp)))
  (define (def-eval exp env)
    (define-var! (cadr exp) (if (list? (caddr exp)) (base-eval (caddr exp) env) (caddr exp)) env))
  (define (if-eval exp env)
    (if (base-eval (car (cdr exp)) env)
 (base-eval (car (cdr (cdr exp))) env)
 (base-eval (car (cdr (cdr (cdr exp)))) env)))
  (define (let-eval exp env)
    (let ((alist (cadr exp)))
      (base-eval (cons (cons 'lambda (cons (map car alist) (cddr exp)))
         (map cadr alist))
   env)))
  (define (quote-eval exp env)
    (cadr exp));; really?
  (define (app-eval exp env)
    (let* ((l (map (lambda (exp) (base-eval exp env)) exp))
    (fun (car l))
    (args (cdr l)))
      (base-apply fun args env)))
  (define (base-apply fun args env)
 (define (makeargs list symbols args); make a list like let form's first arg for environment extention
   (cond ((null? symbols) list)
  (#t (makeargs (cons (cons (car symbols) (car args)) list) (cdr symbols) (cdr args)))))
    (cond ((not (pair? fun))
    (eval-error 'non-function fun))
   ((equal? (car fun) '*lambda*)
    (if (= (length (caddr fun)) (length args))
        (begin
   (let ((arglist (makeargs () (caddr fun) args)))
     (let ((newenv (extend-env arglist (cadr fun))))
       ;; newenvを参照して、function内部のシンボル解決するように
       (base-eval (cadddr fun) newenv))))
        (eval-error 'wrong-number-of-args fun)))
   ((equal? (car fun) '*primitive*)
    (if (or (not (number? (cadr fun))) (= (cadr fun) (length args)))
        ((caddr fun) args env)
        (eval-error 'wrong-number-of-args fun)))
   (#t
    (eval-error 'non-function fun))))
  (define (let-eval exp env)
    (let ((alist (cadr exp)))
      (base-eval (cons (cons 'lambda (cons (map car alist) (cddr exp)))
         (map cadr alist))
   env)))
行 72: 行 37:


make-top-env内のdefine-var!の羅列については課題ページ中の他のprimitive行を見て真似すればいいので省略。


if-evalについて。<<BR>>
これも標準のifを真似るだけ、なのですが、環境とかその辺を考慮してあげないといけないので評価はbase-evalを使います。標準のifを使うのは手抜きっぽい? どうするにせよ評価しない式がある以上、特殊形式は必要だろうから特に恥ずかしい事じゃないよ!
{{{
    (if (base-eval '''expの該当部分''' env)
 (base-eval '''expの該当部分''' env)
 (base-eval '''expの該当部分''' env))
}}}


def-evalについて。<<BR>>
環境の拡張だから前の課題のdefine-var!一発だね! base-evalしてあげることを忘れずにね!


quote-evalについて。<<BR>>
といってもexp、つまり入力のリスト(quote '''hoge''')から必要部分を返すだけなので、
{{{
 (car (cdr exp))
}}}
で。特に難しいところなし。


base-applyで*lambda*をみつけた時の処理について<<BR>>
たぶん課題の真打ちがこれ。とりあえず俺俺処理系に渡されたリストは課題ページの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とか。<<BR>>
fun,argsの中身は中身評価後のcarとcdrで、funはlambda-evalで決めた通り(*lambda* lambda評価時のenv (変数リスト) lambdaの中身)の形をしてかえってくるはずで、argsが残りの部分のリストです。<<BR>>
さて、ここまで落ちつけば、ここでするべきは
 1. ''変数リスト''にあるシンボルに''args''をその順であてはめる。つまり、''lambda評価時のenv''を''lambdaの変数''と''args''で拡張する。
  1. 先の課題のextend-envに渡せるリストを、''変数リスト''と''lambdaの中身''を操作して作る。
  2. extend-envする
 1. ''lambdaの中身''を評価させる事
だとわかります。

Guileだとスタックトレースが見易くて便利らしいけれど、gaucheでもとりあえずは(print hoge)でprintfデバッグすると十分に便利。

とりあえず課題ページの例が動くところまで、ほとんど課題ページの内容をコピペです。ちょこちょこ改訂されてるので一度コピペしなおしてみると便利かも。 自分で書く部分は、

  • make-top-env内のdefine-var!の羅列の中で<,>等を追加

  • base-apply内で*lambda*を見つけた場合の処理
  • def-eval
  • if-eval
  • quote-eval

の五つくらいです。 よって根幹部分はこんな風になります。上にないfoo-evalは課題ページのもので確かOK。beginも簡単だけど、例では使ってないので省略。システムテストも通っちゃう。

  (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
        ((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とか。
fun,argsの中身は中身評価後のcarとcdrで、funはlambda-evalで決めた通り(*lambda* lambda評価時のenv (変数リスト) lambdaの中身)の形をしてかえってくるはずで、argsが残りの部分のリストです。
さて、ここまで落ちつけば、ここでするべきは

  1. 変数リストにあるシンボルにargsをその順であてはめる。つまり、lambda評価時のenvlambdaの変数argsで拡張する。

    1. 先の課題のextend-envに渡せるリストを、変数リストlambdaの中身を操作して作る。

    2. extend-envする
  2. lambdaの中身を評価させる事

だとわかります。


Category読み物

Naoaki Iwakiri/Scheme課題memo (最終更新日時 2011-02-07 03:37:25 更新者 Naoaki Iwakiri)