« SICP 4.1.2 Representing Expressins | Main | SICP 4.1.2 Representing Expressins その2 »

2007.09.06

SICP 4.1.2 Representing Expressins その2

俺様処理系にはデバッグ機能が無い事に気がついた。

それはさておき、僕なりに考えたデバッグ方法。traceを使うと、引数が省略されて困るときがある。特に素人はかなり困る。表示もそうだけど、同じ引数でその手続きだけ実行したいときがある。
CALL cond-clauses (cond ((...) ...) (x 10) (else -3))

トップレベルで、(define bp0 '())みたいに変数を定義しておき、ソースの該当箇所で(set! bp0 exp)のように値を設定しておくと、その関数を抜けた後もそのときの値が見れる。これで、ローカルに作った手続きのデバッグもできそう。頑張れば、bp1→bp2って順繰りに自動で設定することもできそうだ。もっと良い方法は絶対にあるんだけど、当面はこれで十分だ。bpはBreakPointの略。昔作ったROMデバッガの仕組みを思い出したから。

今回はcondからifへの変換の話。俺様処理系には、>とかeq?とかしゃれた演算子はないので、とりあえずこんな感じの手続きを考える。
(cond ((null? x) 5) (x 10) (else -3))

cond-ifによって、cond文が、if文に変換される。ここは俺様処理系とは関係ないので、写経で動くはず。

(cond->if '(cond ((null? x) 5) (x 10) (else -3)))
とすると、こんな式が返る。
(if (null? x)
  5
  (if x
    10
    -3))

良い感じ。

Exercise 4.3 飛ばす

Exercise 4.4 その1 and と orをスペシャルフォームとして実装しなさい。

まずは、普通にeval-oに手続きを追加したバージョン。andとorだと、gaucheのand、orと混乱するので、and-o、or-oにする。

(define (eval-o exp env)
 (cond ((self-evaluating? exp) exp)
    ((variable? exp) (lookup-variable-value exp env))
    ((quoted? exp) (text-of-quotation exp))
    ((call? exp) (apply-o (eval-o (call-operator exp) env)
               (list-of-values (call-operand exp) env)))
    ((assignment? exp) (eval-assignment exp env))
    ((definition? exp) (eval-definition exp env))
    ((if? exp) (eval-if exp env))
    ((and-o? exp) (eval-and (cond-tests exp) env)) ;追加
    ((or-o? exp) (eval-or (cond-tests exp) env))  ;追加
    ((and-d? exp) (eval-o (and->if exp) env))    ;追加
    ((or-d? exp) (eval-o (or->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-o (cond->if exp) env))
    ((application? exp)
     (apply-o (eval-o (operator exp) env)
         (list-of-values (operands exp) env)))
    (else
     (error "Unknown expression type nyo -- EVAL" exp))))

;;;and-oとor-oの実装
;;;and-o
(define (and-o? exp) (tagged-list? exp 'and-o))
(define (eval-and exp env)
 (if (null? exp)
   true
   (if (eval-o (first-operand exp) env)
     (eval-and (rest-operands exp) env)
     false)))
(define (cond-tests exp) (cdr exp))

;;;or-o
(define (or-o? exp) (tagged-list? exp 'or-o))
(define (eval-or exp env)
 (if (null? exp)
   false
   (if (eval-o (first-operand exp) env)
     true
     (eval-or (rest-operands exp) env))))
   

次が、if文への変換。derivedだから、and-d、or-dで実装。

;;;and-d
(define (and-d? exp) (tagged-list? exp 'and-d))
(define (and->if exp) (expand-and (cdr exp)))
(define (expand-and exp)
 (if (null? exp)
   'true
   (let ((first (car exp)) (rest (cdr exp)))
    (make-if first
         (expand-and rest)
         'false))))

;;;or-d
(define (or-d? exp) (tagged-list? exp 'or-d))
(define (or->if exp) (expand-or (cdr exp)))
(define (expand-or exp)
 (if (null? exp)
   'false
   (let ((first (car exp)) (rest (cdr exp)))
    (make-if first
         'true
         (expand-or rest)))))


and-ifの結果
(and->if '(and-d (cond1 'aaa) (cond2 'bbb) (cond3 'ccc)))
gosh> (if (cond1 'aaa) (if (cond2 'bbb) (if (cond3 'ccc) true false) false) false)

'falseの変わりにfalseや#fと書くと、and->ifの戻りに#fが入ってしまい俺様evalで評価できずエラーになった。evalや、true/falseの作りでどうにでもなるけどね。

動くソースはここ


と書いてから、Gaucheクックブックにデバッグのヒントを発見。

|

« SICP 4.1.2 Representing Expressins | Main | SICP 4.1.2 Representing Expressins その2 »

Comments

Post a comment



(Not displayed with comment.)




TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/18154/16361676

Listed below are links to weblogs that reference SICP 4.1.2 Representing Expressins その2:

« SICP 4.1.2 Representing Expressins | Main | SICP 4.1.2 Representing Expressins その2 »