Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Common lisp 查看或提取输入顶级REPL的文本定义,最适合Clozure Common Lisp(CCL)_Common Lisp_Ccl - Fatal编程技术网

Common lisp 查看或提取输入顶级REPL的文本定义,最适合Clozure Common Lisp(CCL)

Common lisp 查看或提取输入顶级REPL的文本定义,最适合Clozure Common Lisp(CCL),common-lisp,ccl,Common Lisp,Ccl,在顶级REPL中工作时,我有时会忘记在运行的lisp系统中输入的定义 我使用Clozure CL,它提供了将应用程序保存为图像的选项,我可以这样做,并且可以在我停止的地方继续,但是在这一点上,不可能查看所有代码,除非我已经单独键入代码并将其保存到xyz文件中 是否有办法获取/提取/查看我输入的定义,以便将其保存为源文件?也许您可以自己轻松实现类似的功能: (defun my-repl (&optional (file-path "cl-history.lisp")) "Saves c

在顶级REPL中工作时,我有时会忘记在运行的lisp系统中输入的定义

我使用Clozure CL,它提供了将应用程序保存为图像的选项,我可以这样做,并且可以在我停止的地方继续,但是在这一点上,不可能查看所有代码,除非我已经单独键入代码并将其保存到xyz文件中


是否有办法获取/提取/查看我输入的定义,以便将其保存为源文件?

也许您可以自己轻松实现类似的功能:

(defun my-repl (&optional (file-path "cl-history.lisp"))
  "Saves commands to a file"
  (loop
    (with-open-file (stream file-path
                            :direction :output
                            :if-does-not-exist :create
                            :if-exists :append) 
      (print '>)
      (let ((input (read)))
        (format stream "~A~%" input)
        (print (eval input))))))
要退出内部循环,应键入
(退出)


或者,您可以使用

或者您可以自己轻松地实现这样的功能:

(defun my-repl (&optional (file-path "cl-history.lisp"))
  "Saves commands to a file"
  (loop
    (with-open-file (stream file-path
                            :direction :output
                            :if-does-not-exist :create
                            :if-exists :append) 
      (print '>)
      (let ((input (read)))
        (format stream "~A~%" input)
        (print (eval input))))))
要退出内部循环,应键入
(退出)


或者,您可以使用

以下命令将提取在包中输入的所有函数定义:

(defun get-all-symbols (&optional package)
  (let ((lst nil)
        (package (find-package package)) )
    (do-all-symbols (s lst)
      (when (fboundp s)
        (unless (and package (not (eql (symbol-package s) package)))
          (push (cons s (function-lambda-expression s)) lst) )))))
尝试以下方法:

(get-all-symbols *package*)

以下内容将提取包中输入的所有函数定义:

(defun get-all-symbols (&optional package)
  (let ((lst nil)
        (package (find-package package)) )
    (do-all-symbols (s lst)
      (when (fboundp s)
        (unless (and package (not (eql (symbol-package s) package)))
          (push (cons s (function-lambda-expression s)) lst) )))))
尝试以下方法:

(get-all-symbols *package*)

以下是与CCL的互动会话:

? (declaim (optimize (debug 3)))
NIL
以上内容在这里不是严格要求的,但是使用高调试级别进行开发并没有什么坏处

? (defun foo (x) (+ 3 x))
FOO
? (inspect 'foo)
[0]     FOO
[1]     Type: SYMBOL
[2]     Class: #<BUILT-IN-CLASS SYMBOL>
        Function
[3]     INTERNAL in package: #<Package "COMMON-LISP-USER">
[4]     Print name: "FOO"
[5]     Value: #<Unbound>
[6]     Function: #<Compiled-function FOO #x3020004B3F7F>
[7]     Arglist: (X)
[8]     Plist: NIL
Inspect> 6
[0]     #<Compiled-function FOO #x3020004B3F7F>
[1]     Name: FOO
[2]     Arglist (analysis): (X)
[3]     Bits: 8388864
[4]     Plist: (CCL::PC-SOURCE-MAP #(17 70 15 22) CCL::FUNCTION-SYMBOL-MAP
        (#(X) . #(63 17 70)) CCL::%FUNCTION-SOURCE-NOTE ...)
[5]     Source Location: #<SOURCE-NOTE Interactive "(defun foo (x) (+ 3 x))">
Inspect 1> 5
[0]     #<SOURCE-NOTE Interactive "(defun foo (x) (+ 3 x))">
[1]     Type: SOURCE-NOTE
[2]     Class: #<STRUCTURE-CLASS SOURCE-NOTE>
[3]     SOURCE: #(40 100 101 102 117 ...)
[4]     FILENAME: NIL
[5]     FILE-RANGE: 23
?(德芬福(x)(3 x))
福
? (检查“foo”)
[0]富
[1] 类型:符号
[2] 类别:#
作用
[3] 包装内部:#
[4] 打印名称:“FOO”
[5] 价值:#
[6] 功能:#
[7] Arglist:(X)
[8] 普利斯特:零
检查>6
[0]     #
[1] 姓名:富
[2] Arglist(分析):(X)
[3] 比特:8388864
[4] Plist:(CCL::PC-SOURCE-MAP#(17 70 15 22)CCL::FUNCTION-SYMBOL-MAP
(#(X)。#(63 17 70))CCL::%FUNCTION-SOURCE-NOTE…)
[5] 源位置:#
检查1>5
[0]     #
[1] 类型:来源说明
[2] 类别:#
[3] 资料来源:#(40100101021117…)
[4] 文件名:NIL
[5] 档案范围:23

您可以看到,即使在REPL中,并且不运行Slime(Slime也可能存储有关Emacs环境的信息),您也可以访问FOO的源代码。如果您知道要恢复哪个函数,可以使用此选项。要录制您的互动课程,请关注运球。

以下是与CCL的互动课程:

? (declaim (optimize (debug 3)))
NIL
以上内容在这里不是严格要求的,但是使用高调试级别进行开发并没有什么坏处

? (defun foo (x) (+ 3 x))
FOO
? (inspect 'foo)
[0]     FOO
[1]     Type: SYMBOL
[2]     Class: #<BUILT-IN-CLASS SYMBOL>
        Function
[3]     INTERNAL in package: #<Package "COMMON-LISP-USER">
[4]     Print name: "FOO"
[5]     Value: #<Unbound>
[6]     Function: #<Compiled-function FOO #x3020004B3F7F>
[7]     Arglist: (X)
[8]     Plist: NIL
Inspect> 6
[0]     #<Compiled-function FOO #x3020004B3F7F>
[1]     Name: FOO
[2]     Arglist (analysis): (X)
[3]     Bits: 8388864
[4]     Plist: (CCL::PC-SOURCE-MAP #(17 70 15 22) CCL::FUNCTION-SYMBOL-MAP
        (#(X) . #(63 17 70)) CCL::%FUNCTION-SOURCE-NOTE ...)
[5]     Source Location: #<SOURCE-NOTE Interactive "(defun foo (x) (+ 3 x))">
Inspect 1> 5
[0]     #<SOURCE-NOTE Interactive "(defun foo (x) (+ 3 x))">
[1]     Type: SOURCE-NOTE
[2]     Class: #<STRUCTURE-CLASS SOURCE-NOTE>
[3]     SOURCE: #(40 100 101 102 117 ...)
[4]     FILENAME: NIL
[5]     FILE-RANGE: 23
?(德芬福(x)(3 x))
福
? (检查“foo”)
[0]富
[1] 类型:符号
[2] 类别:#
作用
[3] 包装内部:#
[4] 打印名称:“FOO”
[5] 价值:#
[6] 功能:#
[7] Arglist:(X)
[8] 普利斯特:零
检查>6
[0]     #
[1] 姓名:富
[2] Arglist(分析):(X)
[3] 比特:8388864
[4] Plist:(CCL::PC-SOURCE-MAP#(17 70 15 22)CCL::FUNCTION-SYMBOL-MAP
(#(X)。#(63 17 70))CCL::%FUNCTION-SOURCE-NOTE…)
[5] 源位置:#
检查1>5
[0]     #
[1] 类型:来源说明
[2] 类别:#
[3] 资料来源:#(40100101021117…)
[4] 文件名:NIL
[5] 档案范围:23
您可以看到,即使在REPL中,并且不运行Slime(Slime也可能存储有关Emacs环境的信息),您也可以访问FOO的源代码。如果您知道要恢复哪个函数,可以使用此选项。对于交互式会话的录制,请遵循关于DRIBBLE的说明。

通用Lisp(一般情况下)不提供任何标准方法来“恢复”编译后的定义源代码。通常,它可以在您使用的任何文件或缓冲区中找到

(正如Leo的回答所指出的,有一个
函数Lambda表达式
,它可以为您提供一些函数定义。它对常量或类没有帮助,也不总是有效的——正如CLHS所说,“任何实现都可以合法地将nil作为任何函数的Lambda表达式返回。”-他的解决方案在最常见的情况下肯定有用,但它并不像这一种情况那样“通用”。)

可以使用一组“包装器”宏,将传递给它们的表单存储在全局哈希表中,然后从中恢复源。写作听起来像是一个有趣的小挑战,下面是我尝试做的事情

我愚蠢的包装解决方案 请注意,以这种方式隐藏的“源”表单不会保留阅读器宏、注释或类似内容,并且可能会以微妙可怕的方式阻塞某些内容,如
defmethod
。这是因为我盲目地存储定义表单中键入的定义-例如,
defun
-以及第二个单词。如果您将函数反弹为宏或泛型函数(所有三个冲突的定义都将被保存),它不会读取方法组合或lambda列表来保存各种方法,或者其中的任何一种,这还不够聪明。你可能会做很多其他的事情,例如,
(SetF(FDefinition'FOO)
,这些事情可能会绕过这些,而不被注意到,所以这远不是“万无一失的”。警告选择器

这里的宏试图从底层表单继承文档和lambda列表,因此它们应该可以很好地与大多数IDE配合使用。他们做得很好,在粘液中

处理这些问题的一种方法是直接给他们打电话;在你的回复中,你可以直接

 My-Package> (use-package :wrap-defining-form)
 My-Package> (defun$ my-fn (x) (+ x (sqrt x)))
在包
包装定义表单中提供了一种更危险/有趣的方法。阴影
,其中宏对真实的
公共Lisp
包定义进行阴影处理

 CL-User> (in-package :CL-USER$)
 CL-User$> (defun blah (n) (loop repeat n do (format t "~&Blah …")))
准备好“保存”内容后,运行
(转储定义)

我在SBCL中编写并测试了它,但我尽力确保它能够在许多/大多数其他实现中工作。特别是,我使用了一个非ANSI函数:
SB Introspect:function Lambda List
。这里的函数
Wrap定义表单::Find-F
NIL
CL-USER> (in-package :Common-Lisp-User/Save-Defs)
#<PACKAGE "COMMON-LISP-USER/SAVE-DEFS">
CL-USER$> (defun 2+ (n) (+ 2 n))
2+
CL-USER$> (describe '2+)
COMMON-LISP-USER/SAVE-DEFS::2+
  [symbol]

2+ names a compiled function:
  Lambda-list: (N)
  Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL))
  Source form:
    (SB-INT:NAMED-LAMBDA 2+
        (N)
      (BLOCK 2+ (+ 2 N)))
; No value
CL-USER$> (macroexpand-1 '(defun 2+ (n) (+ 2 n)))
(COMMON-LISP:DEFUN 2+ (N) (+ 2 N))
T
CL-USER$> (documentation 'defun 'function)
"Wrap `COMMON-LISP:DEFUN' and save the original form.

DEFUN: Define a function at top level."

CL-USER$> (dump-definitions)
;;; definitions as of 2016-12-1 @ 15:32:
(In-Package #:COMMON-LISP-USER/SAVE-DEFS)


(Common-Lisp:Defun 2+ (N) (+ 2 N))

(Common-Lisp:Defun Trash-Word (Word)
  (Let ((S (String Word)))
    (Sort (Remove-If-Not #'Alpha-Char-P S) #'Char<)))
    NIL
     CL-USER$> (dump-definitions "saved.lisp")
     NIL