Here's a case for your consideration. Recently, I wanted to write a macro which looked like 'dolist' but behaved like 'map'. I decided to call it 'collect', and I wanted its usage to be such that I could do the following, for instance.
Code: Select all
> (collect (x '(1 2 3) y '(4 5 6)) (list y x))
((4 1) (5 2) (6 3))
> (collect (x '(1 2 3) y '(4 5 6)) (println y) x)
4
5
6
(1 2 3)
Code: Select all
`(map (fn ,vars ,@body) ,@lists)The following definition is as close as I could get.
Code: Select all
(define-macro (collect)
  (letn ((parms (args 0))
         (plen (length parms))
         (vars (list-nth (sequence 0 (- plen 1) 2) parms))
         (lists (list-nth (sequence 1 (- plen 1) 2) parms))
         (body (1 (args))))
    (comma-expand (map (fn ,vars ,@body) ,@lists))))
; where 'list-nth' is defined as:
(define (list-nth indices lisst)
  (map (fn (n) (nth n lisst)) indices))
My definition of 'comma-expand' is:
Code: Select all
(define-macro (comma-expand form)
  (catch
   (cond ((quote? form)
          (comma-expand-func (eval form) '()))
         ((list? form)
          (eval (comma-expand-func form '())))
         (true form))))
(define (comma-expand-func form acc)
  (cond
    ((not (list? form)) form)
    ((empty? form) (reverse acc))
    ((lambda? form)
     (let ((fn-tail (map (fn (x) x) form))) ; dirty trick.
       (append (lambda) (comma-expand-func fn-tail '()))))
    ((quote? (form 0))
     (comma-expand-func
      (1 form)
      (cons (append '(quote)
                    (list (comma-expand-func (eval (form 0)) '())))
            acc)))
    ((list? (form 0))
     (comma-expand-func (1 form)
                        (cons (comma-expand-func (form 0) '())
                              acc)))
    ((= ', (form 0))
     (if (not (symbol? (form 1))) (throw 'CAN-ONLY-EXPAND-SYMBOLS))
     (let ((sym-name (name (form 1))))
       (if (= "@" (sym-name 0)) ; this means splice is required.
           (letn ((var (symbol (1 sym-name)))
                  (val (eval var)))
             (if (not (list? val)) (throw 'CAN-ONLY-SPLICE-LISTS))
             (comma-expand-func (2 form) (append (reverse val)
                                                 acc)))
         (comma-expand-func (2 form) (cons (eval (form 1)) acc)))))
    (true
     (comma-expand-func (1 form) (cons (form 0) acc)))))