さかもとのブログ

つらつらと

SICP演習問題4.8

なかなか苦戦した.
どうやってlambdaに変換したらよいか.
変換は以下のようにする.

(let loop ((a 5))
  (if (< a 0)
      0
      (+ a (loop (- a 1)))))
;=> 15

((lambda () (define (loop a)
              (if (< a 0) 0 (+ a (loop (- a 1)))))
            (loop 5)))
;=> 15

プログラム読みにくい...一週間後このプログラムがすらすら読めるだろうか.
letを使えば少しすっきりするんだけど,letの定義でletを使うのはやっぱりいやなので,
defineを連呼.

追記(090625)

tagがうまく評価されず,普通の(名前なし)letがうまくできないことが発覚.
とりあえず暫定処置を施す.
if分の中のtagはfalseなのに,bindings, bodyの引数のときは#になる.
わからん......
tagは結局(symbol? cadr exp)なので,それの評価結果をそのまま引数にする.

;;exercise4.8
(define (let-clauses exp)
  (cdr exp))

(define (let-bindings-with-tag exp tag)
  (if tag
      (cadr (let-clauses exp))
      (car (let-clauses exp))))

(define (let-body-with-tag exp tag)
  (if tag
      (cddr (let-clauses exp))
      (cdr (let-clauses exp))))

(define (let-tag exp)
  (if (symbol? (car (let-clauses exp)))
      (car (let-clauses exp))
      #f))

(define (let->combination exp)
  (define tag (let-tag exp))
  (define bindings (let-bindings-with-tag exp (symbol? (cadr exp))))
  (define body (let-body-with-tag exp (symbol? (cadr exp))))
  (if (null? bindings)
      '()
      (if tag
          (list (make-lambda '()
                             (list
                              (cons 'define (cons (cons tag (map car bindings)) body))
                              (cons tag (map cadr bindings)))))
          (cons (make-lambda (map car bindings) body)
                (map cadr bindings)))))