Common lisp 公共lisp中的奇怪语法

Common lisp 公共lisp中的奇怪语法,common-lisp,Common Lisp,我在谷歌搜索时发现了这个lisp函数 (defun filter (lst items-to-filter) (cond ((null lst) nil) ((member (car lst) items-to-filter) #1=(filter (cdr lst) items-to-filter)) (t (cons (car lst) #1#)))) 这只是设置差异,但这是我第一次看到#1=和#1#,语法。我想我通过查看代码就明白了它的意思,但我

我在谷歌搜索时发现了这个lisp函数

(defun filter (lst items-to-filter)
   (cond ((null lst) nil)
         ((member (car lst) items-to-filter) #1=(filter (cdr lst) items-to-filter))
         (t (cons (car lst) #1#))))

这只是设置差异,但这是我第一次看到#1=和#1#,语法。我想我通过查看代码就明白了它的意思,但我不太确定。我认为#1=用于标记表达式,以免以后需要时重新键入它,可以通过#index#引用它,在本例中,index=1。我想知道是否有人能解释一下。这些构造称为什么,是否有它们的参考,以及它们是否在现代lisp代码中广泛使用。感谢在书面源代码中看到它是非常不寻常的。大多数情况下,您会在数据中看到它。它用于创建或打印s表达式中的共享数据项。这样,您也可以读取或打印循环s表达式

您可以使用它更容易地创建重复代码,但通常需要编写函数或宏。函数的优点是它们可以节省代码空间,除非它们是内联的

CL-USER 3 > (pprint '(defun filter (lst items-to-filter)
                       (cond ((null lst) nil)
                             ((member (car lst) items-to-filter)
                              #1=(filter (cdr lst) items-to-filter))
                             (t (cons (car lst) #1#)))))

(DEFUN FILTER (LST ITEMS-TO-FILTER)
  (COND ((NULL LST) NIL)
        ((MEMBER (CAR LST) ITEMS-TO-FILTER)
         (FILTER (CDR LST) ITEMS-TO-FILTER))
        (T
         (CONS (CAR LST) (FILTER (CDR LST) ITEMS-TO-FILTER)))))
正如您在上面看到的,打印机并不是这样打印的。为什么呢? 有一个全局变量
*print circle*
控制它。对于上面的示例,它被设置为
NIL
。让我们改变这一点:

CL-USER 4 > (setf *print-circle* t)
T

CL-USER 5 > (pprint '(defun filter (lst items-to-filter)
                       (cond ((null lst) nil)
                             ((member (car lst) items-to-filter)
                              #1=(filter (cdr lst) items-to-filter))
                             (t (cons (car lst) #1#)))))

(DEFUN FILTER (LST ITEMS-TO-FILTER)
  (COND ((NULL LST) NIL)
        ((MEMBER (CAR LST) ITEMS-TO-FILTER)
         #1=(FILTER (CDR LST) ITEMS-TO-FILTER))
        (T
         (CONS (CAR LST) #1#))))
这表明我们可以在公共Lisp中读取和打印这样的s表达式

共享某些源代码数据结构在计算代码中更为常见:

CL-USER 22 > (defmacro add-1-2-3 (n) `(,n 1 2 3))
ADD-1-2-3

CL-USER 23 > (walker:walk-form '(+ (add-1-2-3 4) (add-1-2-3 5)))
(+ (4 . #1=(1 2 3)) (5 . #1#))

可能的参考资料:第二个
#
调用“reference to”宏。我不知道这个功能的使用是否普遍。lisp的使用很普遍吗?:)这是sharpsign sharpsign reader宏,可以引用以前读取的表单。有关文档,请参阅通用Lisp hyperspec的第2.4.8.16节,例如,在Thank,它实现了以下技巧:D.这里通常使用一个简单的“let”,只计算一次过滤列表。我看不出使用这个技巧有什么好处,但我可能遗漏了一些东西。@Drew因为代码是从不同的分支引用的,所以只会按原样计算一次。我不会像上面那样写它,但是要使用let获得相同的语义,您必须将let放在空检查之后,在这一点上,作者可能会认为#1#比重新分解成嵌套条件更容易。另外一个罕见的用法是为了等式而引用文本对象,而不创建绑定。e、 g.作为宏定义`(lambda(#1=#(gensym))(declare(ignore#1#))…)的一部分,另一个罕见但有用的例子是引用函数的doc字符串,以便我们可以根据需要打印它:(defundo(cmd&restargs)#1=“thisdoit.”(case cmd(:help(print#1#)…)。