(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value 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))))
分り易さのため, evalはcondを使った場合分けとして実装してある. この欠点は, われわれの手続きは識別可能な型しか扱えず, evalの定義を編集せずには新しい型が追加出来ないことである. Lispの殆んどの実装では, 式の型による振分けはデータ主導の流儀で行われている. これにより利用者はeval自身の定義を修正することなく, evalに認識可能な式の新しい型を追加することが出来る. (問題4.3参照)
(define (apply procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) arguments (procedure-environment procedure)))) (else (error "Unknown procedure type -- APPLY" procedure))))
(define (list-of-values exps env) (if (no-operands? exps) '() (cons (eval (first-operand exps) env) (list-of-values (rest-operands exps) env))))
(define (eval-if exp env) (if (true? (eval (if-predicate exp) env)) (eval (if-consequent exp) env) (eval (if-alternative exp) env)))
eval-ifでのtrue?は被実装言語と実装言語の間の接続の問題を明確にする. if-predicateは被実装言語で評価され, 従ってその言語の値を返す. 解釈系の述語true?はその値を, 実装言語のifでテスト出来る値に変換する. 真の値の超循環表現は, 基底のSchemeのそれと同じでないかも知れない.6
(define (eval-sequence exps env) (cond ((last-exp? exps) (eval (first-exp exps) env)) (else (eval (first-exp exps) env) (eval-sequence (rest-exps exps) env))))
(define (eval-assignment exp env) (set-variable-value! (assignment-variable exp) (eval (assignment-value exp) env) env) 'ok)変数の定義も同じように扱う.7
(define (eval-definition exp env) (define-variable! (definition-variable exp) (eval (definition-value exp) env) env) 'ok)ここでは代入や定義の値として記号okを返すようにした.8
基盤のLispの評価の順と無関係に被演算子を左から右へ評価するlist-of-valuesを書け. また被演算子を右から左へ評価するlist-of-valuesを書け.
5
evalの中の
application?節はmapを使用(し, operandsがリストを返すよう要求)する方が, list-of-values手続きをわざわざ書くより簡単だったかも知れない. ここでmapを使わなかったのは, 評価器は, それが扱う言語に
高階手続きがあったとしても, 高階手続きを使わずに実装出来(る, 従って高階手続きを持たない言語ででも書け)るという事実を強調するためである.
6
この場合,
被実装言語と実装言語は同じである. true?の意味を熟考すれば, 物質を乱用せずに
意識を拡大する. [麻薬常習者との連想]
7
殆んどの場合正しく動くがdefineの実装は内部定義の扱いにある微妙な問題を無視している. この問題が何であり,
いかに解決すべきかを, 4.1.6節で見よう.
8
defineとset!を説明した時述べたように, これらの値はSchemeでは実装依存である---つまりどういう値を返すかは実装者が選んでよい.