當(dāng)將用scheme寫的scheme求值器跑起來的時(shí)候,你不覺的興奮是不可能的,真的太酷了,太magic了。
習(xí)題4.2,如果將application?判斷放在define?判斷之前,那么求值(define x 3)將把define當(dāng)作一般的procedure應(yīng)用于參數(shù)x和3,可是define是特殊的語法形式,而非一般過程,導(dǎo)致出錯(cuò)。
習(xí)題4.4,我的解答,eval增加兩個(gè)判斷:
((and? exp)
(eval-and (and-exps exp) env))
((or? exp)
(eval-or (or-exps exp) env))
實(shí)現(xiàn)謂詞和各自的過程:
(define (and? exp)
(tagged-list? exp 'and))
(define (and-exps exp)
(cdr exp))
(define (eval-and exps env)
(cond ((null? exps)
'true)
(else
(let ((result (eval (car exps) env)))
(if (not result)
result
(eval-and (cdr exps) env))))))
(define (or? exp)
(tagged-list? exp 'or))
(define (or-exps exp) (cdr exp))
(define (eval-or exps env)
(cond ((null? exps)
'false)
(else
(let ((result (eval (car exps) env)))
(if result
result
(eval-or (cdr exps) env))))))
如果用宏實(shí)現(xiàn)就簡(jiǎn)單了:
(define-syntax and
(syntax-rules ()
((_) #t)
((_ e) e)
((_ e1 e2 e3
)
(if e1 (and e2 e3
) #f))))
(define-syntax or
(syntax-rules ()
((_) #f)
((_ e) e)
((_ e1 e2 e3
)
(let ((t e1))
(if t t (or e2 e3
))))))
習(xí)題4.5,cond的擴(kuò)展形式,也不難,在else子句之外增加個(gè)判斷,是否帶有=>符號(hào),修改expand-clauses過程:
(define (cond-extended-clauses? clause)
(and (> (length clause) 2) (eq? (cadr clause) '=>)))
(define (extended-cond-test clause)
(car clause))
(define (extended-cond-recipient clause)
(caddr clause)
(define (expand-clauses clauses)
(if (null? clauses)
'false
(let ((first (car clauses))
(rest (cdr clauses)))
(cond ((cond-else-clauses? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "else clause is not LAST" clauses)))
((cond-extended-clauses? first) ;判斷是否擴(kuò)展形式
(make-if
(extended-cond-test first)
(list
(extended-cond-recipient first)
(extended-cond-test first))
(expand-clauses rest)))
(else
(make-if (cond-predicate first)
(sequence->exp (cond-actions first))
(expand-clauses rest)))))))
習(xí)題4.6,let如果用宏定義,類似這樣:
(define-syntax let
(syntax-rules ()
((_ ((x v)
) e1 e2
)
((lambda (x
) e1 e2
) v
))))
求值器擴(kuò)展,實(shí)現(xiàn)let->combination過程:
(define (let? exp)
(tagged-list? exp 'let))
(define (let->combination exp)
(let ((vars (map car (cadr exp)))
(vals (map cadr (cadr exp)))
(body (caddr exp)))
(cons (make-lambda vars (list body)) vals)))
我們做的僅僅是syntax transform,將let轉(zhuǎn)成對(duì)應(yīng)的lambda形式。
習(xí)題4.7,這里的關(guān)鍵在于let*->netsted-lets要遞歸調(diào)用,從let*的宏定義可以看出:
(define-syntax let*
(syntax-rules()
((_ ((var1 val1)) e1
)
(let ((var1 val1)) e1
))
((_ ((var1 val1) (var2 val2)
) e1
)
(let ((var1 val1))
(let* ((var2 val2)
)
e1
)))))
那么,let*->nested-lets可以定義為:
(define (let*? exp)
(tagged-list? exp 'let*))
(define (let*->nested-lets exp)
(let ((pairs (cadr exp))
(body (caddr exp)))
(if (null? (cdr pairs))
(list 'let pairs body)
(list 'let (list (car pairs)) (let*->nested-lets (list 'let* (cdr pairs) body))))))
測(cè)試一下:
(let* ((x 1) (y (+ x 3))) (+ x y)) =》5
習(xí)題4.8,命名let,修改let->combination過程,判斷cadr是pair還是symbol,如果是前者,那就是一般的let,如果是symbol就是命名let語句,那么需要定義一個(gè)名為(cadr exp)的過程放在body里,注意,我們是在做語法轉(zhuǎn)換,因此,這個(gè)定義也應(yīng)該描述成符號(hào),定義一個(gè)make-define過程來生成define語句:
(define (make-define var parameters body)
(list 'define (cons var parameters) body))
然后修改let->combination過程,如上所述:
(define (let->combination exp)
(if (symbol? (cadr exp))
(let ((var (cadr exp))
(vars (map car (caddr exp)))
(vals (map cadr (caddr exp)))
(pairs (caddr exp))
(body (cadddr exp)))
(cons (make-lambda vars (list (make-define var vars body) body)) vals))
(let ((vars (map car (cadr exp)))
(vals (map cadr (cadr exp)))
(body (caddr exp)))
(cons (make-lambda vars (list body)) vals))))
習(xí)題4.1.4,原生的map過程接受的procedure,是以scheme內(nèi)在數(shù)據(jù)結(jié)構(gòu)表示的procedure,而在我們的求值器中,procedure的內(nèi)在數(shù)據(jù)結(jié)構(gòu)取決于我們,與原生的結(jié)構(gòu)不同,導(dǎo)致原生的map無法接受自制求值器的procedure,如果map也以求值器中的結(jié)構(gòu)定義,那么就沒有這個(gè)問題。因此,本質(zhì)上的困難就在于兩個(gè)求值器對(duì)procedure的數(shù)據(jù)結(jié)構(gòu)表示的不同。
習(xí)題4.1.5,著名的圖靈停機(jī)問題,先是假設(shè)存在halts?過程可以正確地判斷任何過程p和對(duì)象a是否p對(duì)a終止,定義了try過程:
(define (try p)
(if (halts? p p)
(run-forever)
'halted))
當(dāng)執(zhí)行(try try),如果這個(gè)過程可終止,那么(halts? try try)應(yīng)該返回false,也就是try過程對(duì)try不會(huì)終止,這與一開始的假設(shè)矛盾;如果這個(gè)過程將無窮運(yùn)行下去,那么(halts? try try)應(yīng)該返回true,也就是try對(duì)try終止,這也與(try try)將無窮運(yùn)行的假設(shè)矛盾。因此,可以推論出,我們不可能寫出一個(gè)過程halts?,使它能正確地判斷任何過程p和對(duì)象a是否p對(duì)a終止。