計算機プログラムの構造と解釈 第二版 P222 問題4.6
今までも何度か出てきたが、letはlambdaで書き換え可能。
「導出された式」として、評価器に実装する。
condの実装を参考にするとやることは、
- evalに加える。
- let?手続き
- let-clauses手続き
- let-parametars手続き (var exp)からなるリストを取り出す
- let-body手続き
- let->combination手続き
- expand-let-clauses手続き
前半5つはほいほいほいと出来る。
let->combination手続きもたいしたことない。
letを外して、expand-let-clausesに渡してやれば良い。
expand-let-clausesの中は結局のところ
make-lambdaをして返せば良いだけと思う。
が、letとlambdaの置き換えの定義をよくみると
(let .... ((lambda...
単なるlambdaではないぞ!
パラメータから、varだけを取り除く処理と、expだけ取り除く処理がかければ後は対したことない。
実装
#!/usr/local/bin/gosh ;; -*- coding: utf-8 -*- (load "./modules/4th.scm") (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)) ;;4.6 ((let? exp) (eval (let->combination exp) env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp)))) ;;4.6 let (define (let? exp) (tagged-list? exp 'let)) (define (let-clauses exp) (cdr exp)) (define (let-parameters clauses) (car clauses)) (define (let-body clauses) (cdr clauses)) (define (let->combination exp) (expand-let-clauses (let-clauses exp))) (define (expand-let-clauses clauses) (if (null? (let-parameters clauses)) '() (cons (make-lambda (map car (let-parameters clauses)) (let-body clauses)) (map cadr (let-parameters clauses))))) (define the-global-environment (setup-environment)) (driver-loop)
実行
;;; M-Eval input: (define (hoge x) (let ((y 100) (z 2)) (+ y (* x z)))) ;;; M-Eval value: ok ;;; M-Eval input: (hoge 1) ;;; M-Eval value: 102