読者です 読者をやめる 読者になる 読者になる

計算機プログラムの構造と解釈 第二版 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