2016-01-28 8 views
0

Особая проблема, с которой я сталкиваюсь, заключается в создании решения для question 4.16b of Structure and Interpretation of Computer Programs. Здесь процедура должна быть создана, что превращаетИзбавление от внешних скобок в списке

(lambda (a b) 
    (define u 'u) 
    (define v 'v) 
    'e1)) 

В:

(lambda (a b) 
    (let ((u '*unassigned*) 
     (v '*unassigned*)) 
    (set! u 'u) 
    (set! v 'v) 
    'e1)) 

Моя процедура (см ниже) не делает этого, но вместо этого превращает ее в:

(lambda (a b) 
    (let ((u *unassigned*) 
     (v *unassigned*)) 
    ((set! u 'u) 
    (set! v 'v)) 
    ('e1))) 

Здесь у нас есть проблема со списком sets! производства make-sets (см. ниже) и остальной частью кузова (('e1) выше), произведенной cons current-element rest-of-body (см. низкий). Они добавляются в списки, в то время как я хочу, чтобы они были как одиночные операторы, т. Е. (set! u 'u) (set! v 'v) вместо ((set! u 'u) (set! v 'v)) и 'e1 вместо `('e1).

Процедура:

;; b. Write a procedure scan-out-defines that takes a procedure body and returns an 
;; equivalent one that has no internal definitions, by making the transformation 
;; described above. 

(define (scan-out expr) 
    (let ((vars (cadr expr)) 
     (body (cddr expr))) 
    (make-lambda vars 
       ; loop over body, 
       ; store all definition names and bodies of the defines 
       ; once finished looping transform those into lets 
       ; where the rest is added to the body 
       (let body-transform ((body-elements body) 
             (definition-names '()) 
             (definition-bodies '()) 
             (rest-of-body '())) 
        (if (null? body-elements) 
        (transform-define-into-let definition-names 
               definition-bodies 
               rest-of-body) 
        (let ((current-element (car body-elements))) 
         (if (tagged-list? current-element 'define) 
         (body-transform (cdr body-elements) 
             (cons (get-definition-name current-element) 
               definition-names) 
             (cons (get-definition-body current-element) 
               definition-bodies) 
             rest-of-body) 
         (body-transform (cdr body-elements) 
             definition-names 
             definition-bodies 
             (cons current-element rest-of-body))))))))) 


(define (tagged-list? exp tag) 
    (if (pair? exp) 
    (eq? (car exp) tag) 
    false)) 

(define (get-definition-name expr) 
    (cadr expr)) 

(define (get-definition-body expr) 
    (caddr expr)) 

(define (transform-define-into-let vars vals rest-of-body) 
    (list (list 'let (make-unassigned-vars vars) 
     (make-sets vars vals) 
     rest-of-body))) 

(define (make-unassigned-vars vars) 
    (let aux ((var-elements vars) 
      (unassigned-vars '())) 
    (if (null? var-elements) 
     unassigned-vars 
     (aux (cdr var-elements) 
      (cons (list (car var-elements) '*unassigned*) unassigned-vars))))) 

(define (make-sets vars vals) 
    (let aux ((var-elements vars) 
      (val-elements vals) 
      (sets '())) 
    (if (null? var-elements) 
     sets 
     (aux (cdr var-elements) 
      (cdr val-elements) 
      (cons (list 'set! (car var-elements) (car val-elements)) sets))))) 

(define (make-lambda parameters body) 
    (cons 'lambda (cons parameters body))) 

; testing 
(scan-out '(lambda (a b) 
      (define u 'u) 
      (define v 'v) 
      'e1)) 

; Should be transformed into: 

; => (lambda (a b) 
;  (let ((u '*unassigned*) 
;   (v '*unassigned*)) 
;  (set! u 'u) 
;  (set! v 'v) 
;  'e1)) 

; But is transformed into: 

; => (lambda (a b) 
;  (let ((u *unassigned*) 
;   (v *unassigned*)) 
;  ((set! u (quote u)) 
;   (set! v (quote v))) 
;  ((quote e1)))) 

То, что я попытался это уплощение списки, как так:

(define (transform-define-into-let definition-names definition-bodies rest-of-body) 
    (list (list 'let (make-unassigned-vars definition-names) 
     (append* (make-sets definition-names definition-bodies)) 
     (append* rest-of-body)))) 

но тогда rest-of-body удаляется только его внешние скобки, make-sets по-прежнему список: например,

(lambda (a b) 
    (let ((u *unassigned*) 
     (v *unassigned*)) 
    ((set! u 'u) 
    (set! v 'v)) 
    'e1)) 

Каков правильный способ избавиться от о f внешние скобки?

Если кто-то может помочь мне с этим, что было бы весьма полезно.

ответ

1

Вы должны изменить:

(define (transform-define-into-let vars vals rest-of-body) 
    (list (list 'let (make-unassigned-vars vars) 
     (make-sets vars vals) 
     rest-of-body))) 

в:

(define (transform-define-into-let vars vals rest-of-body) 
    (list (append (list 'let (make-unassigned-vars vars)) 
       (append (make-sets vars vals) 
         rest-of-body)))) 

, а также:

(define (make-unassigned-vars vars) 
    (let aux ((var-elements vars) 
      (unassigned-vars '())) 
    (if (null? var-elements) 
     unassigned-vars 
     (aux (cdr var-elements) 
      (cons (list (car var-elements) '*unassigned*) unassigned-vars))))) 

в

(define (make-unassigned-vars vars) 
    (let aux ((var-elements vars) 
      (unassigned-vars '())) 
    (if (null? var-elements) 
     unassigned-vars 
     (aux (cdr var-elements) 
      (cons (list (car var-elements) ''*unassigned*) unassigned-vars))))) 

Наконец, обратите внимание, что 'u идентичен (quote u).

+0

Hi Renzo! Большое спасибо!!! : D Достаточно было только изменить 'transform-define-into-let'. Обратите внимание, что 'make-unassigned-vars' не изменился в вашем ответе. ;) –

+0

Добро пожаловать! Обратите внимание, что перед '* unassigned *' есть две одиночные кавычки (''), иначе вы создаете '(u * unassigned *)' вместо '(u '* unassigned *)'. – Renzo

+0

А теперь я вижу. В следующий раз, когда я разберусь с программой вместо своих глаз, прежде чем сказать что-то, не изменилось. По-видимому, цитата - это тождественный оператор, который оценивает себя (один раз) ([источник] (http://www.phyast.pitt.edu/~micheles/scheme/scheme8.html)). То, что я не вижу, заключается в том, почему '' '' a' doe не оценивает 'a' (дважды беря идентификатор). –