Search code examples
macrosschemelisplisp-macros

How to write LISP macro with double quasi quotation in scheme


I need to write the lisp macro in scheme (please on hygienic macros and syntax-rules etc) that will have function call and Alist as argument

I want function and macro that call that function to have syntax like this:

(foo '(10 (a (lambda () (display "10")) b (lambda () (display "20"))))

or macro without quotes.

My last code is working, but not sure if this is how you suppose to write function/macro like this. It seems that I need double backquote but don't know how to write it. (I'm right now reading On Lips by Paul Graham and he said that double backquote is very hard and only need by macros defining macros, but It seems that this is what I need).

(define (foo expr)
    `(list ,(car expr)
           (,(string->symbol "quasiquote") ,(pair-map (lambda (a b)
                                                        (cons (symbol->string a)
                                                              (list 'unquote b)))
                                                      (cadr expr)))))

(define-macro (bar expr)
   (foo expr))

(define xx (bar (10 (a 20 b (lambda () (display "x") (newline))))))
;; (list 10 `((a . ,20) (b . ,(lambda () (display "x") (newline))))
(define bfn (cdr (assoc "b" (cadr xx)))))
(bfn)
;; "x"

and here is definition of pair-map

(define (pair-map fn seq-list)
  "(seq-map fn list)

   Function call fn argument for pairs in a list and return combined list with
   values returned from function fn. It work like the map but take two items from list"
  (let iter ((seq-list seq-list) (result '()))
    (if (null? seq-list)
        result
        (if (and (pair? seq-list) (pair? (cdr seq-list)))
            (let* ((first (car seq-list))
                   (second (cadr seq-list))
                   (value (fn first second)))
              (if (null? value)
                  (iter (cddr seq-list) result)
                  (iter (cddr seq-list) (cons value result))))))))

with (string->symbol "quasiquote") I was able not to use double backquote, can this be written with double backquote/quasiquote? How this should look like?

I'm asking if this can be written different way so I can fix few issues in my own lisp interpreter (not sure if is working correctly but it seems that this final version works the same in guile).


Solution

  • I came up with shorter quasiquote version, but still it require inserting symbols:

    (define (foo expr)
        `(list ,(car expr)
               (,'quasiquote ,(pair-map (lambda (a b)
                                          `(,(symbol->string a) . (,'unquote ,b)))
                                        (cadr expr)))))