2

Doug Hoyte 的“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))))))

表达式“(car a1)”和“(cadr a1)”中的符号“a1”从何而来?

顺便提一句。“定义宏!” 是一个定义宏的宏,它引入了 'g!{symbol}' 语法以通过 'gensym' 创建一个新的符号。'build-batcher-sn'使用Batcher 算法构建排序网络

4

1 回答 1

2

我发现这很奇怪,并且mapcar只会使用一个功能,而 alet不符合条件。因此,必须有其他东西,令人惊讶#`的是一个阅读器宏,它围绕以下表达式创建一个函数:

'#`(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))
于 2018-01-20T22:17:59.073 回答