如何用当前范围打开球拍REPL?

时间:2013-11-09 14:11:11

标签: scheme racket

假设我有一个这样的程序:

(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中探索它们。就我所见。

2 个答案:

答案 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通过在评估程序之前注释语法来做到这一点。来自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中你可能只是发出错误信号来找到好的调试器。