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*))

NILCommon 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とフォームに解析するパッケージが世の中にあり、独自のものを展開するのもそれほど難しくありません。

&aux 変数を使用する

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))
于 2014-10-30T12:15:43.360 に答える