三分's profile3fen's NotebookPhotosBlogListsMore Tools Help

Blog


    September 11

    SICP 4.3.3

    Section 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))))



    Comments

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    Trackbacks

    The trackback URL for this entry is:
    http://3fen.spaces.live.com/blog/cns!19176E6323A90759!352.trak
    Weblogs that reference this entry
    • None