Где "a1" связано в sortf из книги "Пусть над лямбдой"?

Книга Дуга Хойта "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)"?

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

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))
Другие вопросы по тегам