2013-11-09 29 views
3

比方說,我有一個這樣的程序:我如何打開當前範圍的球拍REPL?

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

而且加入電話修改它撬給我一個很好的範圍的REPL,我想它:

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

要做到這一點的JS,我會螢火下運行該程序,只是把一個斷點在第4行:

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

然後我可以在評估窗口中探索一些東西。

有什麼我可以做的就是這球拍?我發現的最接近的是DrScheme的調試器,但它只是提供當前範圍的所有值,並不能讓您在REPL中探究它們,據我所知。

+1

我認爲這是一個很好的問題。幾年前來到Racket,我幾乎沒有人使用調試器,就像我對使用C++的宗教信仰一樣。事實證明,這並不重要。 1.我偶爾使用'log-debug'或'trace'。 2.我在REPL中玩一些小功能,調整和觀察它們。 3.這些功能大多是「功能性」的(不要依靠閱讀或編寫外部狀態)。對於所有這些片段,我幾乎沒有想過再次使用傳統的調試器。說了這麼多,像「pry」這樣的東西聽起來很有趣。 –

回答

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 
> 

但是,儘管它可以讓你訪問拍功能,如+,你不能訪問電子VEN像top-x頂層變量:

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

您可以通過給eval訪問當前命名空間得到頂級的東西,如解釋here。所以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)))) 

而且得到你需要這個咒語,你的調試進程文件這樣的說法:

(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看不到破-EVAL-公式本地綁定,必須實際上是一種數據結構映射X 2和y 3,你想一個辦法讓數據結構。事實上,這樣的數據結構不存在;編譯器可以自由地在編譯時用2替換x的所有用法,以便在運行時x的局部綁定在任何具體意義上都不存在。即使變量不能通過常量摺疊來消除,通常可以消除變量的名稱,並且保存本地值的數據結構不會像從名稱到值的映射。

你可能會說,OK,但是在這種情況下...

如何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 

因此,我認爲這將是起點,如果你想解決這個。

+0

格雷格,我終於有時間跟進你的建議了,而且我遇到了一個障礙,涉及到弄清楚我可以傳遞給註釋功能。如果您有興趣,請查看此處的問題:http://stackoverflow.com/q/21151678/585977 – traffichazard

1

在DrRacked IDE你有DEBUG Q> |按鈕。你可以通過你的程序步驟,或者你可以做你在其他語言中說,在表達按下鼠標右鍵你要調查,要麼選擇繼續這一點以一次爲限或暫停在這一點上一個斷點,然後按GO>運行該程序。

要檢查或更改x,把你的鼠標指針放在它並使用鼠標右鍵。要更改,請在菜單中選擇(set! x ...)

至於語言中的repl,你可以讓你自己的(pry)在那裏啓動一個repl,在Common Lisp中,你可能只是發出了一個錯誤信號去找到好的調試器。

+0

謝謝 - 我意識到這些調試器功能。我真的專注於REPL,因爲這是我最喜歡的調試方式 - 特別是當'x'可能是一個複雜的值時,只是將它打印到屏幕上將是壓倒性的。很高興聽到我可能只想做我自己的撬。我正在考慮這樣做,如果它不是內置的。一個有趣的練習 - 可能是一個電話/ cc的工作... – traffichazard