如何使用当前范围打开球拍 REPL? [英] how do i open a racket REPL with the current scope?

查看:43
本文介绍了如何使用当前范围打开球拍 REPL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say I have a program like this:

(define (foo x) 
  (local 
    ((define y (- x 1)))
    (* x y)))
(foo 3)

我希望能够在第 3 行和第 4 行之间打开一个 REPL,这样我就可以通过执行任意语句来探索(并可能修改)x 和 y 的值.

I want to be able to open a REPL between lines 3 and 4, such that I can explore (and possibly modify) the values of x and y by executing arbitrary statements.

要在 Ruby 中执行此操作,我将采用等效程序:

To do this in Ruby, I would take the equivalent program:

def foo(x)   
  lambda {   
    y = x - 1
    x * y    
  }.call     
end       
puts (foo 3)

并通过添加对 pry 的调用来修改它,以便在我想要的地方给我一个范围很好的 repl:

And modify it by adding a call to pry to give me a nicely-scoped repl where I want it:

require 'pry'
def foo(x)   
  lambda {   
    y = x - 1
    binding.pry
    x * y    
  }.call     
end       
puts (foo 3)

要在 js 中执行此操作,我将在 Firebug 下运行此程序,然后在第 4 行设置断点:

To do it in js, I would run this program under Firebug and just put a breakpoint on line 4:

foo = function(x) {  
  return (function(){
    var y = x - 1;   
    return x * y;    
  })();              
};                                    
console.log(foo(3)); 

然后我可以在评估窗口中探索内容.

And then I could explore stuff in the evaluation window.

我可以做些什么来在 Racket 中获得它?我发现的最接近的是 DrScheme 的调试器,但它只显示当前作用域的所有值,据我所知,它不允许您在 REPL 中探索它们.

Is there anything I can do to get this in Racket? The closest I've found is DrScheme's debugger, but that just presents all the values of the current scope, it doesn't let you explore them in a REPL as far as I can see.

推荐答案

这不是在回答您最初的问题,而是为了回应您关于制作自己的问题的评论.我认为这是一个非常有趣的想法,所以我进行了探索.我能弄清楚的是:

This isn't answering your original question, it's in response to your comment about making your own. I thought that was a really interesting idea so I explored it. What I was able to figure out:

假设您希望它起作用:

(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
> 

但是尽管它允许您访问像 + 这样的 Racket 函数,但您甚至无法访问像 top-x 这样的顶级变量:

But although it lets you access Racket functions like +, you can't access even your top-level variables like top-x:

> (f)
0
1
2
PRY> top-x
; top-x: undefined;
; cannot reference undefined identifier

此处.所以 pry 需要一个命名空间参数:

You can get the top-level stuff by giving eval access to the current namespace, as explained here. So pry needs a namespace argument:

(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))))

并且要获得该参数,您需要将此咒语添加到您的调试文件中:

And to get that argument you need this incantation to your debugee file:

(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:

Now the REPL can see and change 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:

Cool! But it can't change the local variable, i:

> (f)
0
1
2
PRY> i
; i: undefined;
; cannot reference an identifier before its definition

拍摄.原因在这里解释.

您可能会想象,即使 eval 无法看到 break-eval-formula 中的本地绑定,实际上必须有一个数据结构将 x 映射到 2,将 y 映射到 3,并且您想要一种获取该数​​据结构的方法.事实上,不存在这样的数据结构;编译器可以在编译时自由地将 x 的每次使用替换为 2,因此在运行时 x 的本地绑定在任何具体意义上都不存在.即使无法通过常量折叠消除变量,通常也可以消除变量的名称,并且保存局部值的数据结构不像从名称到值的映射.

You might imagine that even though eval cannot see the local bindings in broken-eval-formula, there must actually be a data structure mapping x to 2 and y to 3, and you would like a way to get that data structure. In fact, no such data structure exists; the compiler is free to replace every use of x with 2 at compile time, so that the local binding of x does not exist in any concrete sense at run-time. Even when variables cannot be eliminated by constant-folding, normally the names of the variables can be eliminated, and the data structures that hold local values do not resemble a mapping from names to values.

你可能会说,好吧,但在那种情况下......

You might say, OK, but in that case...

据我所知,DrRacket 通过在评估程序之前注释语法来做到这一点.来自 drracket/gui-debugger/annotator.rkt:

From what I was able to figure out, DrRacket does this by annotating the syntax before evaluating the program. From 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

所以我认为如果你想解决这个问题,那将是一个起点.

So I think that would be the jumping-off point if you wanted to tackle this.

这篇关于如何使用当前范围打开球拍 REPL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆