我在Common Lisp中有另一个涉及自引用的问题.我在Stack Exchange上发现了一个线程,它提出了编写最短程序的问题,该程序将打印程序源代码中不存在的所有可打印ASCII字符.这让我想到如何解决Common Lisp中的问题.我遇到了两个问题 - 一个可能是微不足道的,另一个更棘手:
首先是编写CL脚本的情况,例如从#!/usr/bin/env sbcl --script
.我认为通过*posix-argv*
我可以访问所有命令行参数,包括被调用脚本的名称.我也寻找相当于Bash $0
但却找不到.最终对我有用的是这个丑陋的Bash-ified SBCL脚本,它明确传递$0
给SBCL并从那里继续:
#!/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)))
关于这一点我的问题是:你能否想到任何方式这样做而不依赖于Bash提供相关论点?或者,更简单地说:是否有CL(特别是SBCL)相当于$0
?
现在是我完全困惑的部分.在采用上面的脚本方法之前,我尝试以更加面向REPL的方式实现此目标.基于此线程中的&whole
说明符defmacro
和注意事项,我试图从参数中获取宏的名称,并以某种方式"读入"其源代码.我完全不知道该怎么做.所以简而言之:给定宏的名称,我能以某种方式获得定义它的形式吗?我正在讨论通用解决方案,而不是解析REPL历史.&whole
defmacro
编辑:关于mbratch关于使用macroexpand-1
这里的问题我是怎么做的:
(defmacro self-refer (&whole body) (macroexpand-1 `',body))
通过这个电话,我可以(SELF-REFER)
通过电话获得(SELF-REFER)
.这不是一个解决方案......
我希望有人能指出我正确的方向.谢谢!
在Common Lisp中没有定义获取宏的源代码.
这可能有用(来自LispWorks的例子):
CL-USER 10 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a))) FOO CL-USER 11 > (pprint (function-lambda-expression (macro-function 'foo))) (LAMBDA (DSPEC::%%MACROARG%% #:&ENVIRONMENT1106 &AUX (#:&WHOLE1107 DSPEC::%%MACROARG%%) (#:\(A\ ...\)1108 (CDR #:&WHOLE1107)) (#:CHECK-LAMBDA-LIST-TOP-LEVEL1110 (DSPEC::CHECK-LAMBDA-LIST-TOP-LEVEL '(A B) #:&WHOLE1107 #:\(A\ ...\)1108 2 2 'NIL :MACRO)) (A (CAR (DSPEC::THE-CONS #:\(A\ ...\)1108))) (#:\(B\)1109 (CDR (DSPEC::THE-CONS #:\(A\ ...\)1108))) (B (CAR (DSPEC::THE-CONS #:\(B\)1109)))) (DECLARE (LAMBDA-LIST A B)) (BLOCK FOO `(* (+ ,A ,B) (+ ,A ,A))))
更为深奥的方式是改变现有DEFMACRO
记录来源.许多Lisp实现都有一个称为advising的非标准功能.例如,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是否存在类似的机制,尽管它有一种称为"封装"的东西.