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