exercise 4.1~4.4
4章開始。
gaucheだとうまく実行出来ないので、mzschemeに変えてみた。なんだか悔しい・・・。
ちなみにgaucheだと
;;; M-Eval input: (+ 1 1) gosh: "error": invalid application: ((primitive #<subr +>) 1 1)
とエラー・・・。promitiveなprocedureを呼ぶと揉めるみたい。
むー。
まぁそんなこんなで演習スタート
ex4.1
;;right-to-left (define (list-of-values exps env) (if (no-operands? exps) '() (let ((rest (list-of-values (rest-operands exps) env))) (cons (eval (first-operand exps) env) rest)))) ;;left-to-right (define (list-of-values exps env) (if (no-operands? exps) '() (let ((first (eval (first-operand exps) env))) (cons first (list-of-values (rest-operands exps) env)))))
まぁさして問題はないはず。
ex4.2
a. 例だと define をふつうの関数と認識しちゃうのでダメだろ
b
(define (call? exp) (tagged-list? exp 'call)) (define (call-operater exp) (cadr exp)) (define (call-operands exp) (cddr exp)) (define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((call? exp) (apply (eval (call-operater exp) env) (list-of-values (call-operands exp) env))) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ((cond? exp) (eval (cond->if exp) env)) ;; ((application? exp) ;; (apply (eval (operator exp) env) ;; (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp))))
でおkでしょう。
ex4.3
むー。色々解法がありそう。
自分の例は、
(load "~/src/scheme/putget.scm") (define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((get 'eval (car exp)) ((get 'eval (car exp)) exp env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp)))) (put 'eval 'quote (lambda (exp env) (text-of-quotation exp))) (put 'eval 'set! (lambda (exp env) (eval-assignment exp env))) (put 'eval 'define (lambda (exp env) (eval-definition exp env))) (put 'eval 'if (lambda (exp env) (eval-if exp env))) (put 'eval 'lambda (lambda (exp env) (make-procedure (lambda-parameters exp) (lambda-body exp) env))) (put 'eval 'begin (lambda (exp env) (eval-sequence (begin-actions exp) env))) (put 'eval 'cond (lambda (exp env) (eval (cond->if exp) env)))
ってな感じ。以下の回答もこれ使ってます。
ちなみにputget.scmってのは名前のとおりch3.3.3にあるputとgetのコードをまとめたファイル。
ex4.4
先にletが欲しい・・・
あとclausesと名づけたのは変な気がする・・・
special form
(put 'eval 'and (lambda (exp env) (eval-and (and-clauses exp) env))) (define (and-clauses exp) (cdr exp)) (define (eval-and clauses env) (if (null? clauses) #t (let ((result (eval (car clauses) env))) (if result (if (null? (cdr clauses)) result (eval-and (cdr clauses) env)) 'false)))) (put 'eval 'or (lambda (exp env) (eval-or (or-clauses exp) env))) (define (or-clauses exp) (cdr exp)) (define (eval-or clauses env) (if (null? clauses) #f (let ((result (eval (car clauses) env))) (if result result (eval-or (cdr clauses) env)))))
derived expression
;;4.3のやつ (put 'eval 'or (lambda (exp env) (eval (or->combination exp) env))) (put 'eval 'and (lambda (exp env) (eval (and->combination exp) env))) ;;derived expressions (define (or->combination exp) (expand-or-clauses (cdr exp))) (define (expand-or-clauses clauses) (if (null? clauses) 'false (let ((first (car clauses)) (rest (cdr clauses))) (list (make-lambda '(x) (list (make-if 'x 'x (expand-or-clauses rest)))) first)))) (define (and->combination exp) (expand-and-clauses (cdr exp))) (define (expand-and-clauses clauses) (cond ((null? clauses) 'true) ((null? (cdr clauses)) (car clauses)) (else (make-if (car clauses) (expand-and-clauses (cdr clauses)) 'false))))
ちなみにderived expressionの方は
> (and->combination '(and 1 2 3)) (if 1 (if 2 3 false) false) > (or->combination '(or 1 2)) ((lambda (x) (if x x ((lambda (x) (if x x false)) 2))) 1)
という結果。
orのほうでlambdaつかってるのはletが無かったからw
使わないとtrueの式が二回評価されるので、副作用とか考えるとletで一回縛っておいた方がいい気がしてこうなった。
・・・長くなったのでページ分けます