SICP 読み (145) 4.1.2 式の表現

ちょっと現実トウヒのつもりがハマりそうな予感。(を

問題 4.6

これ、結構厄介なのかなぁ。

gosh> (define sample '(let* ((x 3)
       (y (+ x 2))
       (z (+ x y 5)))
  (* x z)))
sample
gosh> sample
(let* ((x 3) (y (+ x 2)) (z (+ x y 5))) (* x z))
gosh> (cadr sample)
((x 3) (y (+ x 2)) (z (+ x y 5)))
gosh> (list (car (cadr sample)))
((x 3))
gosh> (list 'let (list (car (cadr sample))))
(let ((x 3)))
gosh> 

うーん。無理矢理でっち上がったのが以下。

(define (let*->nested-let exp)
  (define (let*->nested-let-iter arg)
    (cond ((null? arg) '())
	  (else
	   (list 'let (list (car arg)) (let*->nested-let-iter (cdr arg))))))
  (append (let*->nested-let-iter (cadr exp)) (cddr exp)))

gosh に吸わせてみた。

gosh> (define (let*->nested-let exp)
  (define (let*->nested-let-iter arg)
    (cond ((null? arg) '())
	  (else
	   (list 'let (list (car arg)) (let*->nested-let-iter (cdr arg))))))
  (append (let*->nested-let-iter (cadr exp)) (cddr exp)))

let*->nested-let
gosh> (let*->nested-let sample)
(let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) ())) (* x z))
gosh> 

NG。てーか適当感満載だなぁ。あ、null? だったら (cddr exp) を戻せば良さげ。

gosh> (define (let*->nested-let exp)
  (define (let*->nested-let-iter arg)
    (cond ((null? arg) (cddr exp))
	  (else
	   (list 'let (list (car arg)) (let*->nested-let-iter (cdr arg))))))
  (let*->nested-let-iter (cadr exp)))

let*->nested-let
gosh> (let*->nested-let sample)
(let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) ((* x z)))))
gosh> 

このケイスでは caddr で良いのか。

gosh> (define (let*->nested-let exp)
  (define (let*->nested-let-iter arg)
    (cond ((null? arg) (caddr exp))
	  (else
	   (list 'let (list (car arg)) (let*->nested-let-iter (cdr arg))))))
  (let*->nested-let-iter (cadr exp)))

let*->nested-let
gosh> (let*->nested-let sample)
(let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) (* x z))))
gosh> (let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) (* x z))))
39
gosh> 

でもなんか微妙。もう少し賢そうなやり方は無いものか。

'()

'(let ((x 3)))

'(let ((x 3)) (let ((y (+ x 2)))))

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

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

上記のようなデキ上がりになれば良いんでしょうが、不可能な気がするなぁ。いや、cdr が null な car (いっちゃんケツのリスト) に対して append すればデキそう。最後の手続きも同様か。あ、違うな。先頭が let な一番ケツのリストに append か。
なんかデキない事はない気がしますが面倒スギ。試験を考えよう。

試験の検討

なんとか繰り返しにできんかなソレの検討中に、let が入れ子になってたら (手続き部分の中で) どうなるんだろう、と思ってしまった。多分なんとかなるんだろうな。(を

  ("let*->nested-let"
   ("first"
    (let ((l '(let* ((x 3) (y (+ x 2)) (z (+ x y 5))) (* x z)))
	  (result '(let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) (* x z)))))
	  (result2 '((lambda (x) ((lambda (y) ((lambda (z) (* x z)) (+ x y 5))) (+ x 2))) 3)))
      (assert-equal result (let*->nested-let l))
      (assert-equal result2 (let->combination (let*->nested-let l)))
      )
    )
   )

で、上記のような試験をでっち上げてみたら NG との事。

-- (test case) let*->nested-let: F
 expected:<((lambda (x) ((lambda (y) ((lambda (z) (* x z)) (+ x y 5))) (+ x 2))) 3)>
  but was:<((lambda (x) (let ((y (+ x 2))) (let ((z (+ x y 5))) (* x z)))) 3)> in first

ははー。言われてみると確かに見てるのは一発目だけだよな。これ、どうなるんだろ。ちなみに直前エントリで

(eval (let->combination (let*->nested-let exp)) env)

ではないか、と書いてますがこれはこれでビンゴなんだろうか。