2015/12/29
SICP 問題 4.22
letを使えるようにする.
(define (analyze exp)
(cond ((self-evaluating? exp) (analyze-self-evaluating exp))
((quoted? exp) (analyze-quoted exp))
((variable? exp) (analyze-variable exp))
((assignment? exp) (analyze-assignment exp))
((definition? exp) (analyze-definition exp))
((if? exp) (analyze-if exp))
((lambda? exp) (analyze-lambda exp))
((let? exp) (analyze (let->combination exp)))
((begin? exp) (analyze-sequence (begin-actions exp)))
((cond? exp) (analyze (cond->if exp)))
((application? exp) (analyze-application exp))
(else (error "Unknown expression type: ANALYZE" exp))))
(define (let? exp) (tagged-list? exp 'let))
(define (let-parameters exp) (cadr exp))
(define (let-variables exp) (map car (let-parameters exp)))
(define (let-expressions exp) (map cadr (let-parameters exp)))
(define (let-bodys exp) (cddr exp))
(define (let->combination exp)
(if (symbol? (cadr exp)) ;; 2番目の要素がシンボルならnamed-let
(named-let->define (named-let-func-name exp)
(named-let-variables exp)
(named-let-expressions exp)
(named-let-bodys exp))
(cons (make-lambda (let-variables exp)
(let-bodys exp))
(let-expressions exp))))
;; make-procedureのbodyのところについていたscan-out-definesのせいでエラー.
;; make-proceduren渡される時点でbodyはanalyzeした後のclosureになっているので
;; analyze-lambdaの中で内部定義をletに吐き出す.
(define (make-procedure parameters body env)
(list 'procedure parameters body env))
(define (analyze-lambda exp)
(let ((vars (lambda-parameters exp))
(bproc (analyze-sequence (scan-out-defines (lambda-body exp)))))
(lambda (env)
(make-procedure vars bproc env))))