Где привязано 'a1' в sortf из книги Let over Lambda?

Книга Дуга Хойта "Let over Lambda" описывает функцию быстрой сортировки для входных данных фиксированного размера с помощью сетей сортировки :

(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))))))

Откуда появился символ «a1» в выражениях «(car a1)» и «(cadr a1)»?

Кстати. 'defmacro!' - это макрос для определения макросов, который вводит синтаксис 'g! {symbol}' для создания нового символа с помощью 'gensym'. А build-batcher-sn создает сеть сортировки, используя алгоритм дозатора.


person Kasper van den Berg    schedule 20.01.2018    source источник
comment
Спасибо, @Sylwester, на моей клавиатуре планшета нет обратных кавычек.   -  person Kasper van den Berg    schedule 21.01.2018


Ответы (1)


Мне это показалось странным, поскольку mapcar принимает только функцию, а let не подходит. Таким образом, должно быть что-то еще, и сюрприз-сюрприз #` - это макрос-читатель, который создает функцию вокруг следующего выражения:

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

Обратите внимание, что я цитирую его, и, поскольку это макрос для чтения, он все еще расширяется, но результат цитируется. Итак, a1 исходит от читателя-макроса. Вот его определение и активация:

(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|)

И рассматриваемый код:

'#`(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))))

Чтобы использовать больше аргументов, вы добавляете число впереди:

'#2`(list ,a1 ,a2)
; ==> (lambda (a1 a2) `(list ,a1 ,a2))
person Sylwester    schedule 20.01.2018