如何从CL REPL获取函数/宏定义?

 pet宠物情缘 发布于 2023-01-30 11:00

我在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历史.&wholedefmacro

编辑:关于mbratch关于使用macroexpand-1这里的问题我是怎么做的:

(defmacro self-refer (&whole body)
  (macroexpand-1 `',body))

通过这个电话,我可以(SELF-REFER)通过电话获得(SELF-REFER).这不是一个解决方案......

我希望有人能指出我正确的方向.谢谢!

1 个回答
  • 在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是否存在类似的机制,尽管它有一种称为"封装"的东西.

    2023-01-30 11:02 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有