Command line 编写从命令行执行但不在解释器内部执行的公共Lisp代码

Command line 编写从命令行执行但不在解释器内部执行的公共Lisp代码,command-line,common-lisp,slime,sbcl,Command Line,Common Lisp,Slime,Sbcl,在编写公共Lisp代码时,我使用SLIME。特别是,我使用C-C-k编译包含函数定义的缓冲区,然后切换到REPL来运行这些函数。将运行这些函数的可执行代码放在缓冲区中似乎效果不太好。如果代码有bug,它可能会造成混乱 有一种方法可以很方便地包含不在缓冲区中编译但确实从命令行运行的代码,例如在执行以下操作时 sbcl --script foo.lisp 如果是这样的话,我就不必每次想从命令行运行代码时都不断地添加和删除代码。是否存在这种情况 这类似于Python条件 if __name__=='

在编写公共Lisp代码时,我使用SLIME。特别是,我使用C-C-k编译包含函数定义的缓冲区,然后切换到REPL来运行这些函数。将运行这些函数的可执行代码放在缓冲区中似乎效果不太好。如果代码有bug,它可能会造成混乱

有一种方法可以很方便地包含不在缓冲区中编译但确实从命令行运行的代码,例如在执行以下操作时

sbcl --script foo.lisp
如果是这样的话,我就不必每次想从命令行运行代码时都不断地添加和删除代码。是否存在这种情况

这类似于Python条件

if __name__=='__main__':
如果Python文件作为模块导入,则为false;如果作为脚本运行,则为true

这篇名为“随机谷歌”的博客文章

;; 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,如果你把这些添加到你的答案中,我会删除它们

  • 首先,我询问了一种从命令行而不是从解释器运行代码的方法。 提供的解决方案做得更多;它还提供了一种从解释器而不是命令行运行代码的方法

  • 第一步是为宏字符
    #定义一个。
    如链接中所述,“遇到宏字符时,Lisp读取器调用其读取器宏函数”。
    读卡器函数由对的调用定义。
    所以,当
    #字符,则
    设置分派宏字符
    会导致调用正文中定义的lambda函数。 然后,此函数将关键字
    :noscript
    添加到变量中。 另请参见SO问题中有关reader宏的用途的讨论

  • 请注意,关键字
    :noscript
    正是在
    \字符存在。此外,
    #
    当代码在解释器内运行时,例如使用
    slime
    时,字符出现,但程序的
    sbcl的文本--script
    正在运行。因此,当代码在interpeter中运行时,
    :noscript
    被添加到
    *功能*
    中,而不是作为
    剧本

  • 我们现在使用内置读卡器宏
    -/+
    ,正如Vsevolod所说,它的行为类似于to C的
    #IFDEF/#IFNDEF
    。他们检查是否有符号
    *功能中*
    。在这种情况下,
    -:noscript
    检查是否存在
    :noscript
    ,以及
    +:noscript
    检查是否存在
    :noscript

    如果满足这些条件,它将运行相应的代码。要包装代码块,可以使用 像这样:
    #-:noscript(progn)

  • 最后,在运行使用此功能的代码之前,需要调用
    set dispatch macro character
    。在
    sbcl
    的情况下,可以将 它位于初始化文件
    ~/.sbclrc
    中。请注意,这种方法不依赖于SBCL的公共Lisp实现

  • sbcl-devel列表中提到的一个更简单的替代方法是,在
    使用粘液的emacs内部的REPL。SWANK是SLIME的服务器端。黏液应该更准确地称为黏液/SWANK,因为这两个是 客户机/服务器体系结构的客户机/服务器组件。我发现这篇名为的博文很有帮助

    因此,人们可以使用
    -:swank
    +:swank
    就像
    -:noscript
    +:noscript
    一样,只是不需要编写任何代码。 当然,例如,如果使用命令行解释器
    sbcl
    ,这将不起作用, 从那时起,
    :SWANK
    将不会出现在
    *功能*


  • 您可以使用以下技巧:

  • 定义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-k将输出1和3

  • 编辑

    这个技巧应该是有效的,因为当通过SLIME或其他机制加载文件时,shebang行会被
    sbcl--script
    删除,但不会被删除


    这种方法的缺点是,我们的条件是功能中不存在
    :noscript
    ,而不存在
    :script
    。要修改它,应该在
    sbcl--script
    处理本身中推送适当的功能。

    Fare Rideau编写了一个漂亮的unix实用程序CL-Launch,它可以从命令行执行lisp软件。它集成了Quicklisp支持,可用于大多数常见的Lisp实现

    示例脚本可能如下所示:

    #!/usr/bin/cl -sp "hunchentoot" -Q -E main
    
    (defun main (argv)
      (format t "~A: ~{~A ~}~%" (truename ".") argv)
      (hunchentoot:start
       (make-instance 'hunchentoot:acceptor
                      :document-root (truename ".")
                      :port 8080))
      (do ((x #\s (read-char)))
          ((char-equal x #\q) nil)))
    
    在向脚本添加+x权限并调用它之后,它将在当前目录中启动http服务器。“-sp”标志表示要加载的包,因此它是从包中抽象shell脚本的一种相当干净的方法

    有关更多详细信息,请参阅:

    我有同样的问题,我刚刚偶然发现了这个讨论。至少在使用sbcl时,我似乎可以使用
    (sbext:posix getenv“”)
    。当在slime中运行时,它返回
    /usr/bin/emacs
    (或指向emacs的任何路径),否则返回用于调用脚本的命令。因此,在您成为emacs参与者之前,始终可以区分slime和脚本调用:)

    如果你想得到充分的赞扬