三分's profile3fen's NotebookPhotosBlogListsMore ![]() | Help |
|
September 11 SICP 4.3.3Section 4.3.3 当初上数分课,傅里叶级数把我们搞的欲仙欲死,过后到了常微分方程,课上老韩笑着说到了轻松的部分了,就像他爬泰山时候那个“快活三里”。这小节这几个小题是为了巩固amb-eval基础的,4.3整节的最后出现,实在有点“快活三里”的感觉。 4.50 主要不同之处就是amb中的序列是从左到右依次抽取,用的是car cdr,而这里用的是random-choose。 (define (analyze-ramb exp) (let ((cprocs (map analyze (amb-choices exp)))) (lambda (env succeed fail) (define (try-next choices) (if (null? choices) (fail) (let ((random-pick (random-choose choices))) (let ((the-right-one (car random-pick)) (rest-ones (cdr random-pick))) (the-right-one env succeed (lambda() (try-next rest-ones))))))) (try-next cprocs)))) random-choose参数为一个list,结果是一个序对,car为抽取的元素,cdr为其余的。 (define (random-choose seq) (define (random-integer-between low high) (+ low (random (+ (- high low) 1)))) (let ((ref (random-integer-between 1 (length seq)))) (define (foo k items) (if (= k 1) items (let ((foo-next (foo (- k 1) (cdr items)))) (cons (car foo-next) (cons (car items) (cdr foo-next)))))) (foo ref seq))) 应用ramb去实现ex 4.49中的语句生成: 把里面所有的amb全部改为ramb就可以了,这样执行(parse '())就可以生成句子,不过有时动不动就出现几万、几十万字的句子…… 为了控制一下句子的长度,便增加了两个全局变量verb-layer和noun-layer,利用它们控制动词短语和名词短语的层数。 (define verb-layer 0) (define noun-layer 0) 然后在parse-verb-phrase和parse-noun-phrase中控制: (define (parse-verb-phrase) (define (maybe-extend verb-phrase) (require (< verb-layer 3)) (ramb verb-phrase (begin (set! verb-layer (+ 1 verb-layer)) (maybe-extend (list 'verb-phrase verb-phrase (parse-prepositional-phrase)))))) (maybe-extend (parse-word verbs))) (define (parse-noun-phrase) (define (maybe-extend noun-phrase) (require (< noun-layer 3)) (ramb noun-phrase (begin (set! noun-layer (+ 1 noun-layer)) (maybe-extend (list 'noun-phrase noun-phrase (parse-prepositional-phrase)))))) (maybe-extend (parse-simple-noun-phrase))) 每次分析开始都要清0,以便重新构造。 (define (parse-sentence) (set! verb-layer 0) (set! noun-layer 0) (list 'sentence (parse-noun-phrase) (parse-verb-phrase))) 这样,运行(parse '())就可以生成不太长的句子了,而且不断的try-again可以遍历它们!可惜速度有些慢。 ps. 做这题的时候出了点小毛病:开始做的时候random-integer-between中的random部分我没+1,结果代价就是(random-integer-between 1 2)只会出现1.。这一小错不要紧,导致后面的an-element-of只是顺序取值。我当时还是没发现病因,就胡乱猜测ramb不能用an-element-of这种递归形式,而只能用(ramb 1 2 3 4 5)这种(当时竟然没发现这个式子从来第一次没出现过5)。然后又用宏实现了一个amb-eval中类似scheme中的apply过程,这样就可以把多个参数作为一个列表传过来……前后折腾了两个多小时,才走上正道。 4.51 比原来的set!要简单,就是去掉消除副作用的部分就行了。 (define (analyze-permanent-assignment exp) (let ((var (assignment-variable exp)) (vproc (analyze (assignment-value exp)))) (lambda (env succeed fail) (vproc env (lambda (val fail2) (set-variable-value! var val env) (succeed 'ok fail2)) fail)))) 4.52 只要看出aproc应该在cproc的fail部分被调用就明白了。 (define (analyze-if-fail exp) (let ((cproc (analyze (if-fail-consequent exp))) (aproc (analyze (if-fail-alternative exp)))) (lambda (env succeed fail) (cproc env succeed (lambda () (aproc env succeed fail)))))) (define (if-fail-consequent exp) (cadr exp)) (define (if-fail-alternative exp) (caddr exp)) 4.53 生成和为素数的序对,就和当初的map-filter一样。 ((8 35) (3 110) (3 20)) 4.54 (define (analyze-require exp) (let ((pproc (analyze (require-predicate exp)))) (lambda (env succeed fail) (pproc env (lambda (pred-val fail2) (if (false? pred-val) (fail2) (succeed 'ok fail2))) fail)))) TrackbacksThe trackback URL for this entry is: http://3fen.spaces.live.com/blog/cns!19176E6323A90759!352.trak Weblogs that reference this entry
|
|
|