[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: quasiquote implementation



    Your implementation, which is very similar to the T and MIT Scheme
    quasiquote imeplementations, has the powerful advantage over mine of
    conciseness, but it has the serious flaw that it makes the expansion of
    nested quasiquote forms visible to the user, thus making it difficult to
    write portable code to manipulates such forms.  For example, (EQUAL?
    '`(A ,B) ``(A ,B)) doesn't hold in your implementation.  This seems to
    defeat my original aim in suggesting that we standardize the external
    syntax of `, which was to allow people to write portable
    program-manipulating programs.
    
    Jonathan
    
Yes, I see what you mean.  My goal in making the forms standardized
was to to allow portable code such as an interpreter to make sense
out of what the function "read" returns, and also to provide for the
proper pretty-printing of source programs.  I hadn't thought of the
double-quasiquote issue.  When I read your first article, I thought
that you wanted

   '`(A ,B) = ``(A ,B) => (list (quote a) b)

which is relatively easy (but not desirable, since I didn't want to
reach inside the quote).  Instead, I see you want

   '`(A ,B) = ``(A ,B) => `(A ,B)

which I can certainly sympathize with.  This explains the need for
the "level" variable in your code.  For anyone who cares, here is
another (less powerful) version of my code  with a level-tracking
argument added.  I have tested it only briefly.

(let ((check
         (lambda (x)
            (unless (and (pair? (cdr x)) (null? (cddr x)))
                (ferror (car x) "invalid form ~s" x))))
      (quasicons
         (lambda (a d)
            (if (pair? d)
                (if (eq? (car d) 'quote)
                    (if (and (pair? a) (eq? (car a) 'quote))
                        `'(,(cadr a) . ,(cadr d))
                        (if (null? (cadr d))
                            `(list ,a)
                            `(list* ,a ,d)))
                    (if (memq (car d) '(list list*))
                        `(,(car d) ,a ,@(cdr d))
                        `(list* ,a ,d)))
                `(list* ,a ,d)))))
   (define-macro! quasiquote (x)
      (recur f ((x x) (n 0))
         (cond
            ((not (pair? x)) `',x)
            ((eq? (car x) 'quasiquote)
             (check x)
             (quasicons ''quasiquote (f (cdr x) (1+ n))))
            ((eq? (car x) 'unquote)
             (check x)
             (if (zero? n)
                 (cadr x)
                 (quasicons ''unquote (f (cdr x) (1- n)))))
            ((eq? (car x) 'unquote-splice)
             (check x)
             (if (zero? n)
                 (ferror 'unquote-splice "invalid context for ,@~s" (cadr x))
                 (quasicons ''unquote-splice (f (cdr x) (1- n)))))
            ((and (zero? n) (pair? (car x)) (eq? (caar x) 'unquote-splice))
             (check (car x))
             (let ((d (f (cdr x) n)))
                 (if (equal? d '(quote ()))
                     (cadar x)
                     `(append ,(cadar x) ,d))))
            (else (quasicons (f (car x) n) (f (cdr x) n)))))))

(define-macro! unquote (x)
   (ferror 'unquote
      "unquote form ,~s not valid outside of quasiquote"
      x))

(define-macro! unquote-splice (x)
   (ferror 'unquote
      "unquote-splice form ,@~s not valid outside of quasiquote"
      x))