From: Tamas Papp
Subject: "REPL" inside a function
Date: 
Message-ID: <871wfgjnbj.fsf@pu100877.student.princeton.edu>
Is there a way to call a function that would open something like a
REPL inside a function (meaning that I could type in expressions
containing local variables and they would evaluate).  Somewhat like
R's browser().

I am looking for a way to interactively examine what is going on
inside a function when it runs.  I could print some objects, but they
are complex, and I don't know what I am looking for.

If the solution is implementation-specific, I am using SBCL with
SLIME.

Thanks,

Tamas

From: Thomas A. Russ
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <ymisl7wnozt.fsf@sevak.isi.edu>
Tamas Papp <······@gmail.com> writes:

> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().

A standard REPL would not have access to local variables.

> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.

But, the debugger is your friend.

But in a call to 

   (break)

in your code.  That will give you an interactive debugger, the exact
operation of which is implementation specific, but most of them have a
way of showing you the stack trace and letting you examine local
variables.  Using the inspector

  (inspect ...) 

can be a good way to look at complex objects.

To make this work well, you would typically want to include

  (optimize (debug 3) (speed 0) ...)

in your function or environment.  That will typically mean that the
names of local variables will be saved, making looking at the debugger
output a lot simpler.  Some lisp systems have additional variables that
control whether local names are retained or not.  (MCL and OpenMCL come
to mind in that regard.)


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Zach Beane
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <m34pkcutuh.fsf@unnamed.xach.com>
Tamas Papp <······@gmail.com> writes:

> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
> 
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.
> 
> If the solution is implementation-specific, I am using SBCL with
> SLIME.

The normal REPL won't have access to lexical variables, but the
debugger might, depending on your declarations. You can see what's
available by putting (break) in places where you want to stop and
inspect things.

Zach
From: Tamas Papp
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <87wsx8i0id.fsf@pu100877.student.princeton.edu>
Zach Beane <····@xach.com> writes:

> Tamas Papp <······@gmail.com> writes:
>
>> Is there a way to call a function that would open something like a
>> REPL inside a function (meaning that I could type in expressions
>> containing local variables and they would evaluate).  Somewhat like
>> R's browser().
>> 
>> I am looking for a way to interactively examine what is going on
>> inside a function when it runs.  I could print some objects, but they
>> are complex, and I don't know what I am looking for.
>> 
>> If the solution is implementation-specific, I am using SBCL with
>> SLIME.
>
> The normal REPL won't have access to lexical variables, but the
> debugger might, depending on your declarations. You can see what's
> available by putting (break) in places where you want to stop and
> inspect things.

Hi Zach,

I tried that, and I get the following:

break
   [Condition of type SIMPLE-CONDITION]

Restarts:
 0: [CONTINUE] Return from BREAK.
 1: [ABORT] Return to SLIME's top level.
 2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)

Backtrace:
  0: (BREAK "break")

how can I evaluate expressions?  Sorry if this is obvious...

Tamas
From: Zach Beane
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <m3y7hot8uh.fsf@unnamed.xach.com>
Tamas Papp <······@gmail.com> writes:

> Zach Beane <····@xach.com> writes:
>
> > The normal REPL won't have access to lexical variables, but the
> > debugger might, depending on your declarations. You can see what's
> > available by putting (break) in places where you want to stop and
> > inspect things.
> 
> Hi Zach,
> 
> I tried that, and I get the following:
> 
> break
>    [Condition of type SIMPLE-CONDITION]
> 
> Restarts:
>  0: [CONTINUE] Return from BREAK.
>  1: [ABORT] Return to SLIME's top level.
>  2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)
> 
> Backtrace:
>   0: (BREAK "break")
> 
> how can I evaluate expressions?  Sorry if this is obvious...

Type "e". "C-h b" will show you a long list of available commands.

Zach
From: Tamas Papp
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <87sl7whuuf.fsf@pu100877.student.princeton.edu>
Zach Beane <····@xach.com> writes:

> Tamas Papp <······@gmail.com> writes:
>
>> Zach Beane <····@xach.com> writes:
>>
>> > The normal REPL won't have access to lexical variables, but the
>> > debugger might, depending on your declarations. You can see what's
>> > available by putting (break) in places where you want to stop and
>> > inspect things.
>> 
>> Hi Zach,
>> 
>> I tried that, and I get the following:
>> 
>> break
>>    [Condition of type SIMPLE-CONDITION]
>> 
>> Restarts:
>>  0: [CONTINUE] Return from BREAK.
>>  1: [ABORT] Return to SLIME's top level.
>>  2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)
>> 
>> Backtrace:
>>   0: (BREAK "break")
>> 
>> how can I evaluate expressions?  Sorry if this is obvious...
>
> Type "e". "C-h b" will show you a long list of available commands.

I compliled the following:

(defun foo (x)
  (let ((y (1+ x)))
    (break)
    y))

then evaluted (foo 1), which gave me the debugger window

break
   [Condition of type SIMPLE-CONDITION]

Restarts:
 0: [CONTINUE] Return from BREAK.
 1: [ABORT] Return to SLIME's top level.
 2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)

Backtrace:
  0: (BREAK "break")
  1: (FOO 1)
  2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FOO 1) #<NULL-LEXENV>)

Then I went over the backtrace lines above, pressed e, and tried to
evaluate x or y.  Both variables were undefined for all of 0:, 1: and
2:.  What am I doing wrong?

Thanks,

Tamas
From: Zach Beane
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <m3tzsct2ci.fsf@unnamed.xach.com>
Tamas Papp <······@gmail.com> writes:

> I compliled the following:
> 
> (defun foo (x)
>   (let ((y (1+ x)))
>     (break)
>     y))
> 
> then evaluted (foo 1), which gave me the debugger window
> 
> break
>    [Condition of type SIMPLE-CONDITION]
> 
> Restarts:
>  0: [CONTINUE] Return from BREAK.
>  1: [ABORT] Return to SLIME's top level.
>  2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)
> 
> Backtrace:
>   0: (BREAK "break")
>   1: (FOO 1)
>   2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FOO 1) #<NULL-LEXENV>)
> 
> Then I went over the backtrace lines above, pressed e, and tried to
> evaluate x or y.  Both variables were undefined for all of 0:, 1: and
> 2:.  What am I doing wrong?

Try this:

   (defun foo (x)
     (declare (optimize debug))    ; add this line
     (let ((y (1+ x)))
       (break)
       y))

Then, when you are in the debugger, move your cursor to the line that
says:

    1: (FOO 1)

Pressing Enter on that line will show you local variables, and using
"e" while the cursor is there will let you evaluate forms using those
variables.

Zach
From: Tamas Papp
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <87y7hni9k1.fsf@pu100877.student.princeton.edu>
Zach Beane <····@xach.com> writes:

> Tamas Papp <······@gmail.com> writes:
>
>> I compliled the following:
>> 
>> (defun foo (x)
>>   (let ((y (1+ x)))
>>     (break)
>>     y))
>> 
>> then evaluted (foo 1), which gave me the debugger window
>> 
>> break
>>    [Condition of type SIMPLE-CONDITION]
>> 
>> Restarts:
>>  0: [CONTINUE] Return from BREAK.
>>  1: [ABORT] Return to SLIME's top level.
>>  2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {B3C46A9}>)
>> 
>> Backtrace:
>>   0: (BREAK "break")
>>   1: (FOO 1)
>>   2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FOO 1) #<NULL-LEXENV>)
>> 
>> Then I went over the backtrace lines above, pressed e, and tried to
>> evaluate x or y.  Both variables were undefined for all of 0:, 1: and
>> 2:.  What am I doing wrong?
>
> Try this:
>
>    (defun foo (x)
>      (declare (optimize debug))    ; add this line
>      (let ((y (1+ x)))
>        (break)
>        y))
>
> Then, when you are in the debugger, move your cursor to the line that
> says:
>
>     1: (FOO 1)
>
> Pressing Enter on that line will show you local variables, and using
> "e" while the cursor is there will let you evaluate forms using those
> variables.

Great!  Even pressing RET on it will show the variables.

Thanks a lot,

Tamas
From: aleph
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <1184082087.769010.243640@g4g2000hsf.googlegroups.com>
On Jul 10, 5:22 pm, Tamas Papp <······@gmail.com> wrote:
> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
>
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.
>
> If the solution is implementation-specific, I am using SBCL with
> SLIME.

you could use the "REP" something like this (print (eval (read)))))
From: Drew Crampsie
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <4693a908$0$16309$88260bb3@free.teranews.com>
On Tue, 10 Jul 2007 17:22:24 +0200, Tamas Papp wrote:

> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
> 
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.

I've been know to stick a call to INSPECT right in the middle of a
function i'm debugging. Much the same is sticking in a BREAK and using the
debugger. The latter will likely play nicer with slime, but may not have
the same information.

drewc

> 
> If the solution is implementation-specific, I am using SBCL with SLIME.
> 
> Thanks,
> 
> Tamas

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Drew Crampsie
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <4693a90b$0$16309$88260bb3@free.teranews.com>
On Tue, 10 Jul 2007 17:22:24 +0200, Tamas Papp wrote:

> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
> 
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.

I've been know to stick a call to INSPECT right in the middle of a
function i'm debugging. Much the same is sticking in a BREAK and using the
debugger. The latter will likely play nicer with slime, but may not have
the same information.

drewc

> 
> If the solution is implementation-specific, I am using SBCL with SLIME.
> 
> Thanks,
> 
> Tamas

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Pascal Bourguignon
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <87k5t8njzo.fsf@thalassa.lan.informatimago.com>
Tamas Papp <······@gmail.com> writes:

> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
>
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.
>
> If the solution is implementation-specific, I am using SBCL with
> SLIME.

There may be implementation- or even slime- specific solutions.
Here is a portable Common Lisp one.

You can easily write your own REPL, or use google groups.

From that, you can transport a lexical environment, but you have to
explicitely build it, since there is no Common Lisp operator to get
the current lexical environment.  Here is how it's done for lexical
variables and lexical functions.  You can modify it for other lexical
stuff, like block names, etc.


(defmacro handling-errors (&body body)
  `(HANDLER-CASE (progn ,@body)
     (simple-condition 
         (ERR) 
       (format *error-output* "~&~A: ~%" (class-name (class-of err)))
       (apply (function format) *error-output*
              (simple-condition-format-control   err)
              (simple-condition-format-arguments err))
       (format *error-output* "~&")
       (finish-output))
     (condition 
         (ERR) 
       (format *error-output* "~&~A: ~%  ~S~%"
               (class-name (class-of err)) err)
       (finish-output))))


(defmacro capture-lexical-environment (variables &optional functions)
  `(list :environment
         (list ,@(mapcar
                  (lambda (var)
                    (let ((val (gensym)))
                      `(list ',var (lambda () ,var) (lambda (,val) (setf ,var ,val)))))
                  variables))
         (list ,@(mapcar (lambda (fun) `(list ',fun (function ,fun))) functions))))


(defun compile-environment (environment)
  "
Not really compiling, we just prepare the flet and symbol-macrolet bindings
to avoid doing that several times."
  (cond
    ((atom environment)
     (error "Expected an environment, not: ~S" environment))
    ((eq (first environment) :compiled-environment) environment)
    ((eq (first environment) :environment)
     (let* ((variables (mapcar (lambda (var) (cons (gensym) var))
                               (second environment)))
            (functions (third environment)))
       (list :compiled-environment
             ;; flet:
             `(,@(mapcan
                  (lambda (var)
                    `((,(first var) () (funcall ,(third var)))
                      ((setf ,(first var)) (value)
                       (funcall ,(fourth var) value))))
                  variables)
                 ,@(mapcar (lambda (fun)
                             `(,(first fun) (&rest args)
                                (apply ,(second fun) args)))
                           functions))
             ;; Symbol-macrolet:
             (mapcar
              (lambda (var) `(,(second var) (,(first var))))
              variables))))
    (t (error "Expected an environment, not: ~S" environment))))


(defun eval-in-environment (form environment)
  (let ((environment (compile-environment environment)))
    (eval `(flet ,(second environment)
              (symbol-macrolet ,(third environment)
                ,form)))))


(defun lexical-repl (environment)
  (do ((+eof+  (gensym))
       (environment (compile-environment environment))
       (hist 1 (1+ hist)))
      (nil)
    (format t "~%~A[~D]> " (package-name *package*) hist)
    (finish-output)
    (handling-errors
     (setf - (read *standard-input* nil +eof+))
     (when (or (eq - +eof+)
               (member - '((quit)(exit)(continue)) :test (function equal)))
       (return-from lexical-repl))
     (let ((results (multiple-value-list
                     (eval-in-environment - environment))))
       (shiftf +++ ++ + -)
       (shiftf /// // / results)
       (shiftf *** ** * (first /)))
     (format t "~& --> ~{~S~^ ;~%     ~}~%" /)
     (finish-output))))



C/USER[25]> (let ((x 1)
                  (y 0)
                  (bindings '((y) (inc dec))))
              (flet ((inc () (incf x))
                     (dec () (decf x)))
                (lexical-repl (capture-lexical-environment (bindings y) 
                                                           (inc dec)))
                (list x y)))
COMMON-LISP-USER[1]> x
SIMPLE-UNBOUND-VARIABLE: 
EVAL: variable X has no value       ; since it hasn't be "captured"

COMMON-LISP-USER[1]> bindings
 --> ((Y) (INC DEC))

COMMON-LISP-USER[2]> y
 --> 0

COMMON-LISP-USER[3]> (setf y 3)

 --> 3

COMMON-LISP-USER[4]> (inc)

 --> 2

COMMON-LISP-USER[5]> (inc)

 --> 3

COMMON-LISP-USER[6]> (inc)

 --> 4

COMMON-LISP-USER[7]> (dec)

 --> 3

COMMON-LISP-USER[8]> (quit)

(3 3)
C/USER[27]> 



That said, most debuggers offer basically this feature, so it may be
enough to break in the debugger, like in:
http://www.cliki.net/TutorialClispDebugger


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Slobodan Blazeski
Subject: Re: "REPL" inside a function
Date: 
Message-ID: <1184140458.423741.203520@o61g2000hsh.googlegroups.com>
On Jul 10, 5:22 pm, Tamas Papp <······@gmail.com> wrote:
> Is there a way to call a function that would open something like a
> REPL inside a function (meaning that I could type in expressions
> containing local variables and they would evaluate).  Somewhat like
> R's browser().
>
> I am looking for a way to interactively examine what is going on
> inside a function when it runs.  I could print some objects, but they
> are complex, and I don't know what I am looking for.
>
> If the solution is implementation-specific, I am using SBCL with
> SLIME.
>
> Thanks,
>
> Tamas

Not what you want but trace might give you some values to look at.