Lisp 如何从CL REPL获取函数/宏定义?
我还有一个问题涉及到公共Lisp中的自我引用。我发现了一个问题,即编写最短的程序来打印程序源代码中不存在的所有可打印ASCII字符。这让我想到了如何用CommonLisp解决这个问题。我遇到了两个问题——一个可能很琐碎,另一个更棘手:Lisp 如何从CL REPL获取函数/宏定义?,lisp,common-lisp,sbcl,self-reference,Lisp,Common Lisp,Sbcl,Self Reference,我还有一个问题涉及到公共Lisp中的自我引用。我发现了一个问题,即编写最短的程序来打印程序源代码中不存在的所有可打印ASCII字符。这让我想到了如何用CommonLisp解决这个问题。我遇到了两个问题——一个可能很琐碎,另一个更棘手: 首先是编写CL脚本的情况,例如,以#开头/usr/bin/env sbcl--脚本。我认为通过*posix argv*我可以访问所有命令行参数,包括被调用脚本的名称。我还查找了Bash$0的等价物,但没有找到。最终对我有效的是这个丑陋的Bash-ified SB
- 首先是编写CL脚本的情况,例如,以
。我认为通过#开头/usr/bin/env sbcl--脚本
我可以访问所有命令行参数,包括被调用脚本的名称。我还查找了Bash*posix argv*
$0的等价物,但没有找到。最终对我有效的是这个丑陋的Bash-ified SBCL脚本,它显式地将
传递给SBCL,并从中继续:$0
关于这一点,我的问题是:你能想出一种不依赖Bash提供相关参数的方法吗?或者,更简单地说:是否存在相当于#!/bin/bash #| sbcl --script $0 $0 exit |# (defun file-string (path) (with-open-file (stream path) (let ((data (make-string (file-length stream)))) (read-sequence data stream) data))) (let* ((printable (mapcar #'code-char (loop for i from #x20 to #x7e collect i))) (absent (set-difference printable (coerce (file-string (cadr *posix-argv*)) 'list)))) (print (coerce absent 'string)))
的CL(特别是SBCL)$0
- 现在是我完全困惑的部分。在使用上面的脚本方法之前,我试图以一种更面向REPL的方式实现这个目标。基于
中的defmacro
说明符和中的考虑因素,我试图从&whole
参数中获取宏的名称,并以某种方式“读入”其源。我完全不知道怎么做。因此,简而言之:给定宏的名称,我能否以某种方式获得定义它的&whole
表单?我说的是一个通用的解决方案,而不是解析REPL历史 编辑:关于mbratch关于使用defmacro
的问题,我是这样做的:macroexpand-1
通过此调用,我可以通过调用(defmacro self-refer (&whole body) (macroexpand-1 `',body))
获得(自引用)
。这不是一个很好的解决方案(自引用)
我希望有人能给我指出正确的方向。谢谢 在Common Lisp中未定义获取宏的源 这可能会起作用(来自LispWorks的示例): 更深奥的方法是修改现有的
DEFMACRO
,以记录其源代码。
许多Lisp实现都有一个称为建议的非标准特性。例如,LispWorks可以建议宏:
CL-USER 31 > (defadvice (defmacro source-record-defmacro :after)
(&rest args)
(setf (get (second (first args)) :macro-source) (first args)))
T
上面将代码添加到标准的DEFMACRO
宏,该宏将源记录在宏名称的符号属性列表中defmacro
是要建议的内容的名称source record defmacro
是此建议的选定名称<代码>:after然后指定代码应在正常的defmacro
代码之后运行
CL-USER 32 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER 33 > (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
同样,这是完全非标准的——我不确定SBCL是否存在类似的机制,尽管它有一种叫做“封装”的机制。这是对Rainer Joswig的LispWorks解决方案的一个非常晚的后续行动。我最近一直在使用Allegro CL,发现了这个设施。从概念上讲,它与上面的
defadvice
非常相似,而且更加详细。以下是Rainer在ACL 10.0中示例的重新迭代:
(def-fwrapper source-record-defmacro (&rest args)
(setf (get (second (first args)) :macro-source) (first args))
(call-next-fwrapper))
定义了一个fwrapper
之后,您需要明确地“将其付诸实施”:
(fwrap 'defmacro 'srd 'source-record-defmacro)
在这之后,就像雷纳的例子:
CL-USER> (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER> (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
; No value
对于(1)您可以使用posix argv作为参数,加载路径名作为被调用脚本的实际名称。谢谢,mbratch。这使事情简化了很多。对于(2)你看过
macroexpand-1
了吗?是的,我看过,但不幸的是,它只做了所需的一部分。如果我计算如下内容:(defmacro-self-reference(&whole-body)`(macroexpand-1',body))
我得到的响应是(macroexpand-1'(self-reference))
,它是self-reference
宏的主体,但不是整个定义。这很难满足程序访问其整个源代码的要求。您希望/试图如何使用自引用
?也许第二个项目中的试用代码示例有助于澄清问题陈述。Rainer,您的第一个示例在SBCL和Clozure CL中返回了nil
。至于第二个,我没有找到多少关于在SBCL中使用enclosure
的建议,但CMUCL手册包含一些信息。我会尝试调整你的解决方案。无论如何,你的回答只能让我相信,LispWorks比我想象的要酷得多。
CL-USER> (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER> (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
; No value