我想打印,如标题中所述,我的整个功能。
(DEFUN X () ...)
-> (DEFUN X () ...)
我需要写什么" ..." ?
答案 0 :(得分:5)
#1=(defun x () (write '#1# :circle t))
答案 1 :(得分:1)
Lars的答案很聪明,使用圆形结构来指代源中的源。对于一般内省目的而言可能更有用的另一个选项是定义一个特殊变量,该变量提供对正在定义的表单的访问。这是一个初始但不完美的版本:
(defpackage #:introspective-common-lisp
(:use "COMMON-LISP")
(:shadow "DEFUN")
(:nicknames #:icl))
(in-package #:icl)
(defvar *current-form* nil
"The current form being evaluated (typically a definition form.")
(defmacro defun (&whole form name lambda-list &body body)
"Like CL:DEFUN, except that within BODY, *CURRENT-FORM* is bound to
the defining ICL:DEFUN form."
`(cl:defun ,name ,lambda-list
(let ((*current-form* ',form))
,@body)))
(defun x ()
"A function that prints its source."
(print *current-form*))
CL-USER> (in-package #:icl)
#<PACKAGE "INTROSPECTIVE-COMMON-LISP">
ICL> (x)
(DEFUN X
NIL
(PRINT *CURRENT-FORM*))
(DEFUN X
NIL
(PRINT *CURRENT-FORM*))
请注意,NIL
和()
在Common Lisp中是相同的,因此(defun x () ...)
与(defun x nil ...)
相同。当然,您可以检查*current-form*
的值并决定打印()
,但这里的重点是您可以访问该表单,现在您可以自由打印它了想要(或做任何你想要的东西)。
使用Common Lisp的宏设备,这实际上是一件非常简单的事情,我能够在很短的时间内将这一点拼凑在一起。但是,有一些细微之处需要注意。在此初始版本中,我将自定义icl:defun
宏展开为
`(cl:defun ,name ,lambda-list
(let ((*current-form* ',form))
,@body)))
但这会使body
的声明错位。这真的需要像:
`(cl:defun ,name ,lambda-list
,@(util:body-declarations body)
(let ((*current-form* ',form))
,@(util:body-forms body)))
有些软件包会将一个正文解析为声明/文档字符串和表单,而且也不难推出自己的函数。
您也可以完全跳过let
,并将&aux
变量添加到cl:defun
的lambda列表中,但为了做到这一点,您需要检查是否lambda列表中已经存在&aux
关键字,因为您不希望添加冗余关键字。这并不难,但它确实使我们的代码变得更复杂:
(eval-when (:compile-toplevel :load-toplevel :execute)
(cl:defun with-aux-variable (lambda-list name &optional value)
"Returns a new lambda list like LAMBDA-LIST (which should be an
ordinary lambda list), but with an NAME as an &aux variable with the
specified VALUE."
(let ((tail (if (member '&aux lambda-list)
(list (list name value))
(list '&aux (list name value)))))
(append lambda-list tail)))
) ; eval-when
(defmacro defun (&whole form name lambda-list &body body)
"Like CL:DEFUN, except that within BODY, *CURRENT-FORM* is bound to
the defining ICL:DEFUN form."
`(cl:defun ,name ,(with-aux-variable lambda-list
'*current-form*
(list 'quote form))
,@body))