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

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

そもそもcondにこんな機能がついてたなんて知らないんだけど。
使い方は教科書のとおり。

実際にやってみると、できるのでできるんだなぁと思う。

condの修正は前のページでやっていた導出された式で使われてたcondのexpand-clausesを修正すれば良さそう。

もともとはこんな感じ

(define (expand-clauses clauses)
  (if (null? clauses)
    'false                          ; no else clause
    (let ((first (car clauses))
          (rest (cdr clauses)))
      (if (cond-else-clause? first)
        (if (null? rest)
          (sequence->exp (cond-actions first))
          (error "ELSE clause isn't last -- COND->IF"
                 clauses))
        (make-if (cond-predicate first)
                 (sequence->exp (cond-actions first))
                 (expand-clauses rest))))))

じとーッと眺めていると、make-ifに与える引数を帰れば良さそう。
ちなみにmake-ifはこんな感じです。

(define (make-if predicate consequent alternative)
  (list 'if predicate consequent alternative))

predicateにあたる引数はこのままな感じ
consequentが変わる。
sequence->expをみてみると、

(define (sequence->exp seq)
  (cond ((null? seq) seq)
        ((last-exp? seq) (first-exp seq))
        (else (make-begin seq))))

複数の式があった場合に、beginをつける位のしょりだから、
普通にリスト形式で返せば良いかと思います。

後小さいことなんだけど、assoc、cadrをprimitive-proceduresに付け足さないと、
教科書に載っているコードが機能しない。

#!/usr/local/bin/gosh
;; -*- coding: utf-8 -*-
(print (cond ((assoc 'b '((a 1) (b 2))) => cadr)
             (else false)))


(load "./modules/4th.scm")

(define (expand-clauses clauses)
  (if (null? clauses)
    'false
    (let ((first (car clauses))
          (rest (cdr clauses)))
      (if (cond-else-clause? first)
        (if (null? rest)
          (sequence->exp (cond-actions first))
          (error "ELSE clause isn't last -- COND->IF"
                 clauses))
        (make-if (cond-predicate first)
                 (let ((predicate (cond-predicate first))
                       (action (cond-actions first)))
                   (if (eq? (car action) '=>)
                     (list (cadr action) predicate)
                     (sequence->exp action)))
                 (expand-clauses rest))))))


(define primitive-procedures
  (list (list 'car car)
        (list 'cdr cdr)
        (list 'cadr cadr)
        (list 'cons cons)
        (list 'null? null?)
        (list '+ +)
        (list '* *)
        (list 'assoc assoc) ;; 4.5
        ;  <基本手続きが続く>
        ))

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


実行

2


;;; M-Eval input:
(cond ((assoc 'b '((a 1) (b 2))) => cadr)
(else false))

;;; M-Eval value:
2

始めの2はプリミティブでの実行。