command-line - 编写从命令行执行但不在解释器内部执行的Common Lisp代码

标签 command-line common-lisp slime sbcl

在编写Common Lisp代码时,我使用SLIME。特别是,我使用C-C C-k编译了包含函数定义的缓冲区,然后切换到REPL来运行那些函数。将可执行代码放到缓冲区中运行那些功能似乎效果不佳。如果代码中有错误,可能会造成困惑。

有一种方法可以方便地包含未在缓冲区中编译但可以从命令行运行的代码,例如做的时候

sbcl --script foo.lisp

如果是这种情况,那么我每次想从命令行运行代码时都不必继续添加和删除代码。是否存在这样的条件?

这类似于Python条件。
if __name__=='__main__':

如果将Python文件作为模块导入,则为false;如果作为脚本运行,则为true。

通过随机谷歌搜索发现的这个名为"Using SBCL for Common Lisp shell scripting"的博客文章具有
;; If run from command line, the following if-test will succeed

(if (> (length sb-ext:*posix-argv*) 1)

    ;; Code that is executed from the command line only goes here

)

所包含的代码确实不会由SLIME内的编译器运行,但也不会由sbcl --script运行。

更新:感谢Vsevolod Dyomkin的有益回答和后续行动。
接下来是有关该答案的一些注释,这些注释是从注释中整理出来的。
@Vsevolod,如果将它们添加到答案中,我将其删除。
  • 首先,我要求一种从命令行而不是从解释器运行代码的方法。
    提供的解决方案提供了更多功能;它还提供了一种从解释器而不是命令行运行代码的方法。
  • 第一步是为宏字符#!定义reader macro function
    如链接“在遇到宏字符时,Lisp阅读器将调用其阅读器宏功能”中所述。
    阅读器功能由对 set-dispatch-macro-character 的调用定义。
    因此,当看到#!字符时,set-dispatch-macro-character导致调用主体中定义的lambda函数。
    然后,此函数将关键字:noscript添加到 *features* 变量中。
    另请参见有关SO宏对读者宏有什么好处的讨论
    Read macros: what do you use them for?
  • 请注意,当存在:noscript字符时,正是将关键字*features*添加到#!中。此外,#!当代码在解释器中运行时出现字符,例如使用slime时,但显然不存在(已删除)在程序的
    运行sbcl --script的文本。因此,当代码在interpeter中运行时,将:noscript添加到*features*中,但当以
    脚本。
  • 我们现在使用内置的读取器宏#-/#+,正如Vsevolod所说的,其行为类似于C的#IFDEF/#IFNDEF。他们检查符号
    *features*中。在这种情况下,#-:noscript检查是否存在:noscript#+:noscript检查是否存在:noscript
    如果满足这些条件,它将运行相应的代码。要包装一段代码,可以使用
    progn 像这样:#-:noscript (progn <your code here>)
  • 最后,在运行使用此功能的代码之前,需要先调用set-dispatch-macro-character。在sbcl的情况下,可以放
    在初始化文件~/.sbclrc中。请注意,此方法不取决于Common Lisp实现为SBCL。
  • 如sbcl-devel列表中所述,一个更简单的替代方法是使用以下事实:当在其中键入:SWANK时出现关键字*features*
    使用SLIME在emacs中使用REPL。 SWANK是SLIME的服务器端。 SLIME应该更准确地称为SLIME/SWANK,因为这两个是
    客户端-服务器体系结构的客户端/服务器组件。我发现此博客文章Understanding SLIME很有帮助。

    因此,除了不需要编写任何代码之外,可以像#-:swank#+:swank一样使用#-:noscript#+:noscript
    当然,如果使用命令行解释器sbcl,则此方法将无效,例如,
    从那时起,:SWANK将不会出现在*features*中。
  • 最佳答案

    您可以使用以下技巧:

  • 为shebang定义一个调度函数:
    (set-dispatch-macro-character #\# #\!
        (lambda (stream c n)
          (declare (ignore c n))
          (read-line stream)
          `(eval-when (:compile-toplevel :load-toplevel :execute)
             (pushnew :noscript *features*))))
    
  • 在脚本文件中,使用#-:noscript:
    #!/usr/local/bin/sbcl --script
    
    (defun test (a) (print a))
    
    (test 1)
    #-:noscript (test 2)
    #+:noscript (test 3)
    

    执行./test.lisp将输出1和2,而C-c C-k将输出1和3。

  • 编辑

    此技巧应该有效,因为通过SLIME或其他机制加载文件时,shebang行已被sbcl --script完全删除,但未被删除。

    这种方法的缺点是我们要以要素中不存在:noscript而不是:script为条件。要对其进行修改,应在sbcl --script处理本身中完成对适当功能的推送。

    关于command-line - 编写从命令行执行但不在解释器内部执行的Common Lisp代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9796353/

    相关文章:

    c - 段错误 11

    matlab - 将终端下的Matlab不可见图保存为相同大小的图像

    common-lisp - Hunchentoot 启用 CORS

    algorithm - 查找列表元素的任意长度子集

    Java 命令行错误 (linux) - 无法找到或加载主类

    使用 Visual Studio 2005 的 C 编译错误

    lisp - 打印分成 X 列的长列表

    opengl - 将 cl-opengl 与着色器结合使用

    emacs - Swank 服务器启动失败

    带有 slime-fancy 的 clojure 和 common lisp 的 emacs 设置 (slime-autodoc)