SICP問題4.8
名前付きlet
(let <var> <bindings> <body>)
名前付きletで定義したfib手続き
(define (fib n) (let fib-iter ((a 1) (b 0) (count n)) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))))
これは以下と同じである
(define (fib n) (define (fib-iter a b count) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))) (fib-iter 1 0 n))
と思ったんだけど、これだと二つのリスト返さないといけないのでbeginで包み込まないとダメなので以下のように書き換えを行う
(define (fib n) (begin (define (fib-iter a b count) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))) (fib-iter 1 0 n)))
今回の書き換えとは関係ないけど、以下とも同じ
(define (fib n) (letrec ((fib-iter (lambda (a b count) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))))) (fib-iter 1 0 n)))
ということで、上の書き換えからlet関連の手続きを修正する
(define (let? exp) (tagged-list? exp 'let)) (define (named-let? exp) ; 追加 (and (let? exp) (not (pair? (cadr exp))))) (define (let-parameters exp) ; 修正 (if (named-let? exp) (caddr exp) (cadr exp))) (define (let-body exp) ; 修正 (if (named-let? exp) (cdddr exp) (cddr exp))) (define (let-variables exp) (map car (let-parameters exp))) (define (let-expressions exp) (map cadr (let-parameters exp))) (define (let-name exp) ; 追加 (cadr exp)) (define (make-definition variable body) ; 追加 (list 'define variable body)) (define (let->combination exp) ; 修正 (if (named-let? exp) (if (null? (let-parameters exp)) '() (make-begin (list (make-definition (let-name exp) (make-lambda (let-variables exp) (let-body exp))) (cons (let-name exp) (let-expressions exp))))) (if (null? (let-parameters exp)) '() (cons (make-lambda (let-variables exp) (let-body exp)) (let-expressions exp)))))