假设我有一个这样的程序:
(define (foo x)
(local
((define y (- x 1)))
(* x y)))
(foo 3)
我希望能够在第3行和第4行之间打开一个REPL,这样我就可以通过执行任意语句来探索(并可能修改)x和y的值。
要在Ruby中执行此操作,我将采用等效的程序:
def foo(x)
lambda {
y = x - 1
x * y
}.call
end
puts (foo 3)
通过添加对pry的调用来修改它,在我想要的地方给我一个很好的范围的repl:
require 'pry'
def foo(x)
lambda {
y = x - 1
binding.pry
x * y
}.call
end
puts (foo 3)
要在js中执行此操作,我将在Firebug下运行此程序,并在第4行放置一个断点:
foo = function(x) {
return (function(){
var y = x - 1;
return x * y;
})();
};
console.log(foo(3));
然后我可以在评估窗口中探索内容。
在Racket中我能做些什么吗?我发现的最接近的是DrScheme的调试器,但它只是呈现了当前范围的所有值,它不会让你在REPL中探索它们。就我所见。
答案 0 :(得分:2)
这不是回答你原来的问题,而是回应你对自己做出的评论。我认为这是一个非常有趣的想法所以我探索了它。我能够弄清楚:
假设你想要这个:
(define top-x 10)
(define (f)
(for ([i 10])
(displayln i)
(when (= i 5)
(pry)))) ; <= drop into a REPL here, resume after exiting REPL
首次尝试pry
:
(define (pry)
(let loop ()
(display "PRY> ")
(define x (read))
(unless (or (eof-object? x) (equal? x '(unquote exit)))
(pretty-print (eval x))
(loop))))
这似乎有效:
> (f)
0
1
2
PRY> (+ 10 10)
20
PRY> ,exit
3
4
>
但是虽然它允许您访问+
之类的球拍功能,但您甚至无法访问top-x
等顶级变量:
> (f)
0
1
2
PRY> top-x
; top-x: undefined;
; cannot reference undefined identifier
如here所述,您可以通过eval
访问当前命名空间来获取顶级资料。所以pry
需要一个名称空间参数:
(define (pry ns)
(let loop ()
(display "PRY> ")
(define x (read))
(unless (or (eof-object? x) (equal? x '(unquote exit)))
(pretty-print (eval x ns)) ; <---
(loop))))
为了获得这个论点,你需要这个咒语到你的debugee文件:
(define-namespace-anchor a) ; <---
(define ns (namespace-anchor->namespace a)) ; <---
(define top-x 10)
(define (f)
(for ([i 5])
(displayln i)
(when (= i 2)
(pry ns)))) ; <---
现在,REPL可以查看和更改top-x
:
> (f)
0
1
2
PRY> top-x
10
PRY> (set! top-x 20)
#<void>
PRY> top-x
20
PRY> ,exit
3
4
>
酷!但它无法更改局部变量i
:
> (f)
0
1
2
PRY> i
; i: undefined;
; cannot reference an identifier before its definition
拍摄。解释原因here。
您可能会想到,即使eval无法在broken-eval-formula中看到本地绑定,实际上必须有一个数据结构映射x到2和y到3,并且您想要一种获取该数据结构的方法。实际上,不存在这样的数据结构;编译器可以在编译时自由地将x的每次使用替换为2,因此x的本地绑定在运行时不具有任何具体意义。即使不能通过常量折叠消除变量,通常也可以消除变量的名称,并且保存局部值的数据结构不会类似于从名称到值的映射。
你可能会说,好的,但在那种情况下......
从我能够弄清楚,DrRacket通过在评估程序之前注释语法来做到这一点。来自drracket/gui-debugger/annotator.rkt:
;; annotate-stx inserts annotations around each expression that introduces a
;; new scope: let, lambda, and function calls. These annotations reify the
;; call stack, and allows to list the current variable in scope, look up
;; their value, as well as change their value. The reified stack is accessed
;; via the CURRENT-CONTINUATION-MARKS using the key DEBUG-KEY
所以我认为如果你想解决这个问题,那将是一个起点。
答案 1 :(得分:1)
在DrRacked IDE中,您有一个 DEBUG Q&gt; | 按钮。您可以单步执行程序,也可以按照其他语言的说法进行操作,在要调查的表达式上按鼠标右键,然后选择继续此点一次或暂停此时表示断点,然后按 GO&gt; 运行该程序。
要检查或更改x
,请将鼠标指针放在上面并使用鼠标右键。要更改,请在菜单中选择(set! x ...)
。
对于in语言repl,你可以让你自己的(pry)
在那里开始一个repl,在Common Lisp中你可能只是发出错误信号来找到好的调试器。