1

如标题所述,我想打印我的整个功能。

(DEFUN X () ...)

-> (DEFUN X () ...)

我需要在“...”中写什么?

4

2 回答 2

5
#1=(defun x () (write '#1# :circle t))
于 2014-10-29T11:51:11.997 回答
1

定义一个记录源的 my:defun

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*并决定打印(),但这里的重点是您可以访问该表单,并且您现在可以随意打印它(或用它做任何您想做的事情) )。

更好的申报处理

通过解析body

使用 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)))

有一些包可以将正文解析为声明/文档字符串和表单,而且你自己的也不太难。

通过使用 &aux 变量

您也可以let完全跳过,并在 的 lambda 列表中添加一个&aux变量cl:defun,但要做到这一点,您需要检查&auxlambda 列表中是否已经有一个关键字,因为您不想添加多余的一个。这并不难做到,但它确实使我们的代码更复杂了一点:

(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))
于 2014-10-30T12:15:43.360 回答