macroscommon-lispsorting-networklet-over-lambda

Where is 'a1' bound in sortf from the book Let over Lambda?


The book "Let over Lambda" by Doug Hoyte describes a fast sorting function for fixed sized inputs via sorting networks:

(defmacro! sortf (comperator &rest places)
  (if places
    `(tagbody
      ,@(mapcar
        #`(let ((,g!a #1=,(nth (car a1) places))
                (,g!b #2=,(nth (cadr a1) places)))
            (if (,comperator ,g!b ,g!a)
              (setf #1# ,g!b
                    #2# ,g!a)))
        (build-batcher-sn (length places))))))

Where does the symbol 'a1' in the expressions '(car a1)' and '(cadr a1)' come from?

Btw. 'defmacro!' is a macro to define macros that introduces 'g!{symbol}' syntax to create a fresh symbol via 'gensym'. And 'build-batcher-sn' builds a sorting network using Batcher's algorithm.


Solution

  • I found this strange as well as mapcar will only take a function and a let does not qualify. Thus there has to be something else and surpris surprise #` is a reader-macro that creates a function around the expression that follows:

    '#`(list a b c) 
    ; ==> (lambda (a1) `(list a b c))
    

    Notice I quote it and since it's a read-macro it still expands but the result gets quoted. So a1 comes from the reader-macro. Here is it's definition and activation:

    (defun |#`-reader| (stream sub-char numarg)
      (declare (ignore sub-char))
      (unless numarg (setq numarg 1))
      `(lambda ,(loop for i from 1 to numarg
                      collect (symb 'a i))
         ,(funcall
            (get-macro-character #\`) stream nil)))
    
    (set-dispatch-macro-character
      #\# #\` #'|#`-reader|)
    

    And the code in question:

    '#`(let ((,g!a #1=,(nth (car a1) places))
                    (,g!b #2=,(nth (cadr a1) places)))
                (if (,comperator ,g!b ,g!a)
                  (setf #1# ,g!b
                        #2# ,g!a)))
    ; ==>
    (lambda (a1)
     `(let ((,g!a ,(nth (car a1) places)) 
            (,g!b ,(nth (cadr a1) places)))
       (if (,comperator ,g!b ,g!a) 
           (setf ,(nth (car a1) places) ,g!b ,(nth (cadr a1) places) ,g!a))))
    

    To make use of more arguments you add the number in front:

    '#2`(list ,a1 ,a2)
    ; ==> (lambda (a1 a2) `(list ,a1 ,a2))