Где "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))