EoPL reading (108) 2.3 Representation Strategies for Data Types
とりあえず Exercise 2.17 は昨晩のナニで OK ってコトにします。
実装が以下。
(define eopl:error error) (define empty-env (lambda () (lambda (cmd sym) (if (eqv? cmd 'pred) #f (eopl:error 'apply-env "No binding for ~s" sym))))) (define extend-env (lambda (syms vals env) (lambda (cmd sym) (let ((pos (list-find-position sym syms))) (if (number? pos) (list-ref vals pos) (if (eqv? cmd 'pred) (has-association? env sym) (apply-env env sym))))))) (define apply-env (lambda (env sym) (env 'apply sym))) (define has-association? (lambda (env sym) (env 'pred sym))) (define list-find-position (lambda (sym los) (list-index (lambda (sym1) (eqv? sym1 sym)) los))) (define list-index (lambda (pred ls) (cond ((null? ls) #f) ((pred (car ls)) 0) (else (let ((list-index-r (list-index pred (cdr ls)))) (if (number? list-index-r) (+ list-index-r 1) #f))))))
上記だと has-association? で変数の束縛が見つかった時に #t が戻りません。ので試験が以下な形になってます。
(use gauche.test) (add-load-path ".") (load "Fig2.3") (test-start "has-association") (test-section "has-association") (test* "(has-association? (empty-env) 'a) returns #f" #f (has-association? (empty-env) 'a)) (test* "(has-association? ((a b) (1 2)) 'c) returns #f" #f (has-association? (extend-env '(a b) '(1 2) (empty-env)) 'c)) (test* "(not (has-association? ((a b) (1 2)) 'a)) returns #f" #f (not (has-association? (extend-env '(a b) '(1 2) (empty-env)) 'a))) (test-end)
has-association? で変数束縛を確認した時点で #t を戻すのであれば、extend-env が戻す手続きが以下になってれば良いのですが
(lambda (cmd sym) (let ((pos (list-find-position sym syms))) (if (number? pos) (if (eqv? cmd 'pred) #t (list-ref vals pos)) (if (eqv? cmd 'pred) (has-association? env sym) (apply-env env sym)))))))
これはあまりにキタナいカンジ。もうすこし簡潔にならんかな、と言いつつ以降が面白そうなのと、scheme 的に以下の評価はあり、という事でこれでヨシ、って事にします。
$ gosh gosh> (add-load-path ".") ("." "/usr/share/gauche/site/lib" "/usr/share/gauche/0.8.13/lib") gosh> (load "Fig2.3") #t gosh> (define l (extend-env '(a b) '(1 2) (empty-env))) l gosh> l #<closure (extend-env extend-env)> gosh> (if (has-association? l 'a) (apply-env l 'a)) 1 gosh>
条件式が #f でなければ if は #t である、と判断する、ってコトで。
この後
ReadingGauche 方面に出力した後に、smart.fm して 2.3.3 方面に着手予定。