計算機プログラムの構造と解釈 第二版 P222 問題4.7

導出するだけで十分だと思う。なんかできてると思うし。

基本的にこの一個前の問題とやり方は一緒。

  • evalに加える。
  • let*?手続き
  • let*-clauses手続き
  • let*-parametars手続き (var exp)からなるリストを取り出す
  • let*-body手続き
  • let*->nested-lets手続き
  • expand-let*-clauses手続き

あと書き換えできるように

  • make-let

がいる。letの書き方がわかれば、別に難しくはない。

まず、let*をletで書き換えるとこんな感じになるかと。
こいつが、、、

  (let* ((x 3)
         (y (+ x 2)) 
         (z (+ x y 5)))
    (* x z))

こうなる、、、

  (let ((x 3)) 
    (let ((y (+ x 2))) 
      (let ((z (+ x y 5))) 
        (* x z))))

こういう書き換えを行ってあげれば良い。
用は単なるletの入れ子だから、問題4.6のにまたletが入る感じ


実装

#!/usr/local/bin/gosh
;; -*- coding: utf-8 -*-

(print
  (let* ((x 3)
         (y (+ x 2))
         (z (+ x y 5)))
    (* x z)))


(print
  (let ((x 3)) 
    (let ((y (+ x 2))) 
      (let ((z (+ x y 5))) 
        (* x z)))))


(load "./modules/4th.scm")
(load "./modules/let.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))

        ;;4.7
        ((let*? exp) (eval (let*->nested-lets exp) env))

        ((application? exp)
         (apply (eval (operator exp) env)
                (list-of-values (operands exp) env)))
        (else
          (error "Unknown expression type -- EVAL" exp))))


;;4.7 let*
(define (let*? exp) (tagged-list? exp 'let*))

(define (let*-clauses exp) (cdr exp))

(define (let*-parameters clauses) (car clauses))

(define (let*-body clauses) (cadr clauses))

(define (make-let* defs body)
  (list 'let defs body))

(define (let*->nested-lets exp)
  (expand-let*-clauses (let*-clauses exp)))


(define (expand-let*-clauses clauses)
  (if (null? clauses)
    '()
    (let ((parameters (let*-parameters clauses))
          (body (let*-body clauses)))
      (define (expand-let*-clauses-i rest-parameters)
        (if (null? rest-parameters)
          body
          (make-let* (list (car rest-parameters))
                     (expand-let*-clauses-i (cdr rest-parameters)))))
      (expand-let*-clauses-i parameters))))


(define the-global-environment (setup-environment))
(driver-loop)

実行

39
39


;;; M-Eval input:
  (let* ((x 3)
         (y (+ x 2)) 
         (z (+ x y 5)))
    (* x z))

;;; M-Eval value:
39

始めの39はlet*とその書き換えを確かめたやつ。