2013-11-09 3 views
3

Скажем, у меня есть программа, как это:Как открыть ракетку REPL с текущей областью?

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

Я хочу, чтобы иметь возможность открыть REPL между линиями 3 и 4, так что я могу исследовать (и, возможно, изменить) значения х и у по выполнение произвольных операторов.

Чтобы сделать это в 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, я бы запустить эту программу под Firebug и просто поставить точку останова на строке 4:

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

И тогда я мог бы исследовать материал в окне оценки.

Есть ли что-нибудь, что я могу сделать, чтобы получить это в Racket? Самое близкое, что я нашел, - это отладчик 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 
> 

Но, хотя он позволяет вам получить доступ к функциям Racket, например +, вы не можете получить доступ к e ажа переменного верхнего уровня, как 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)))) 

И получить тот аргумент, что нужно это колдовство в файл 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)))) ; <--- 

Теперь РЕПЛ можно увидеть и изменить 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 

Shoot. Причина объясняется here.

Вы можете себе представить, что даже если Eval не может видеть локальные привязки в разорванной Eval-формуле, должно быть на самом деле структура данных, отображение х 2, а у 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 

Так что я думаю, что бы точка трамплин, если вы хотите, чтобы решить это.

+0

Грег. У меня наконец есть время, чтобы следить за вашими советами, и я столкнулся с блокпостом, связанным с выяснением, какой именно синтаксис я могу передать аннотированная функция. Если вам интересно, ознакомьтесь с вопросом здесь: http://stackoverflow.com/q/21151678/585977 – traffichazard

1

В DrRacked IDE у вас есть DEBUG Q> | кнопка. Вы можете выполнить свою программу или сделать так, как вы сказали на других языках, нажмите правую кнопку мыши в выражении, которое хотите исследовать, и либо выберите . Продолжайте до этого пункта только один раз или пауза в этой точке для точки останова , затем нажмите GO>, чтобы запустить программу.

Чтобы проверить или изменить x, наведите указатель мыши на него и используйте правую кнопку мыши. Для изменения вы выбираете (set! x ...) в меню.

Что касается переписки по языку, вы можете сделать свой собственный (pry), чтобы начать его там, и в Common Lisp вы могли просто сообщить об ошибке, чтобы добраться до хорошего отладчика.

+0

Спасибо - я знал об этих функциях отладчика. Я действительно после REPL специально, потому что это мой любимый способ отладки - особенно когда 'x' может быть сложным значением, и просто распечатать его на экране будет подавляющим. Приятно слышать, что я могу просто хотеть сделать свою собственную подделку. Я думал об этом, если он еще не был встроен. Интересное упражнение - возможно, работа для звонка/cc ... – traffichazard

Смежные вопросы