2014-10-29 115 views

回答

5
#1=(defun x() (write '#1# :circle t)) 
+0

這是quine,但不是OP所要求的 - 「一種打印自身的功能」。 – coredump 2014-10-29 15:30:46

+0

非常感謝:) – 2014-10-31 11:58:42

1

定義我:defun定義,記錄源

拉斯的答案是一個聰明的一個,使用循環結構指的是內源的來源。另一個可能對於一般內省目的更有用的選項是定義一個特殊變量,以提供對正在定義的表單的訪問。這裏有一個初步,但並不完全拋光,版本:

(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列表中的一個&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)) 
+0

謝謝你這樣準確的答案:) – 2014-10-31 11:58:10