タイトルに記載されているように、関数全体を印刷したいと思います。
(DEFUN X () ...)
-> (DEFUN X () ...)
「…」には何を書く必要がありますか?
タイトルに記載されているように、関数全体を印刷したいと思います。
(DEFUN X () ...)
-> (DEFUN X () ...)
「…」には何を書く必要がありますか?
#1=(defun x () (write '#1# :circle t))
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)))
本文を宣言/docstringとフォームに解析するパッケージが世の中にあり、独自のものを展開するのもそれほど難しくありません。
let
完全にスキップして、&aux
変数をcl:defun
のラムダ リストに追加することもできますが、それをうまく行うに&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))