I'm writing a recursive function, and I find myself asking, how many
invocations of this function are currently on the stack? What's the
value of a local variable 5 invocations down the stack? I could give
the function an extra argument that contained a list of states the
function had gone through, but this seems wrong:
(defun f (args &optional history)
...
(setf local-state (make-hash-table))
...
(f (cdr args) (cons local-state history))
Is there a better way to do this in Lisp? Is this something
continuations do? If there's a resource I should read, I would
appreciate a pointer.
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
|
|
0
|
|
|
|
Reply
|
ari (61)
|
7/8/2007 11:29:17 PM |
|
Ari Krupnik wrote:
> I'm writing a recursive function, and I find myself asking, how many
> invocations of this function are currently on the stack? What's the
> value of a local variable 5 invocations down the stack? I could give
> the function an extra argument that contained a list of states the
> function had gone through, but this seems wrong:
>
> (defun f (args &optional history)
> ...
> (setf local-state (make-hash-table))
> ...
> (f (cdr args) (cons local-state history))
>
>
> Is there a better way to do this in Lisp? Is this something
> continuations do? If there's a resource I should read, I would
> appreciate a pointer.
As with most things, how one goes about doing something probably depends
on what it is that one wants to do. For example, I'm guessing that
something like the following is not really what you're looking for. Or
is it?
CL-USER 21 > (defun f (n)
(when (= n 0)
(break))
(f (1- n)))
F
CL-USER 22 > (f 5)
Break.
1 (continue) Return from break.
2 (abort) Return to level 0.
3 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other
options
CL-USER 23 : 1 > :b
Interpreted call to F
Interpreted call to F
Interpreted call to F
Interpreted call to F
Interpreted call to F
Interpreted call to F
Call to EVAL
Call to CAPI::CAPI-TOP-LEVEL-FUNCTION
Call to CAPI::INTERACTIVE-PANE-TOP-LOOP
Call to (SUBFUNCTION MP::PROCESS-SG-FUNCTION MP::INITIALIZE-PROCESS-STACK)
CL-USER 24 : 1 > :v
Interpreted call to F:
N : 0
CL-USER 25 : 1 > :n
Interpreted call to F
CL-USER 26 : 1 > :n
Interpreted call to F
CL-USER 27 : 1 > :n
Interpreted call to F
CL-USER 28 : 1 > :v
Interpreted call to F:
N : 3
CL-USER 29 : 1 > :c 4
No such restart.
NIL
CL-USER 30 : 1 > :?
:ed Edit the function associated with the frame
:v Print the current frame
:bq Print a quick backtrace of interesting call frames
:b Print a backtrace down from the current frame
:error Print the error and how to continue
:n Go down the stack
:p Go up the stack
:top Abort to top level
:a Abort one level
:c Continue from error
:ret Return from frame
:res Restart frame
:sres Restart frame, stepping the function
:trap Cause the debugger to be re-entered on exit from this frame
:< Go to the top of the stack
:> Go to the bottom of the stack
:cc Get the current condition object
:all Set the debugger options to show all call frames
:l Print and return the value of a given variable in the current
frame.
:func Get the function ovject in the current frame
:bb Print a full backtrace suitable for a bug report
:lambda Show the lambda expression for an anonymous interepreted frame
:bug-form <subject> &key <filename>
Print out a bug report form, optionally to a file.
:get <variable> <command identifier>
Get a command from the history list and put it in a variable.
:help Produce this list.
:his &optional <n1> <n2>
List the command history, optionally the last n1 or range n1
to n2.
:redo &optional <command identifier>
Redo a previous command, identified by its number or a substring.
:use <new form> <old form> &optional <command identifier>
Redo command after replacing old form with new form.
NIL
CL-USER 30 : 1 > :c 3
CL-USER 31 >
|
|
0
|
|
|
|
Reply
|
dkixk (148)
|
7/9/2007 1:12:28 AM
|
|
Damien Kick <dkixk@earthlink.net> writes:
> Ari Krupnik wrote:
>> I'm writing a recursive function, and I find myself asking, how many
>> invocations of this function are currently on the stack? What's the
>> value of a local variable 5 invocations down the stack? I could give
>> the function an extra argument that contained a list of states the
>> function had gone through, but this seems wrong:
>>
>> (defun f (args &optional history)
>> ...
>> (setf local-state (make-hash-table))
>> ...
>> (f (cdr args) (cons local-state history))
>
> As with most things, how one goes about doing something probably
> depends on what it is that one wants to do. For example, I'm guessing
> that something like the following is not really what you're looking
> for. Or is it?
>
> CL-USER 21 > (defun f (n)
> (when (= n 0)
> (break))
> (f (1- n)))
> F
I was looking for something I could do from inside the function, not
the REPL. In the example I gave, I can find out how deep the recursion
is by looking at (length history), for example.
Ari
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
|
|
0
|
|
|
|
Reply
|
ari (61)
|
7/10/2007 12:17:01 AM
|
|
In article <86d4z2scdu.fsf@deb.lib.aero.>, Ari Krupnik <ari@lib.aero>
wrote:
> I'm writing a recursive function, and I find myself asking, how many
> invocations of this function are currently on the stack? What's the
> value of a local variable 5 invocations down the stack? I could give
> the function an extra argument that contained a list of states the
> function had gone through, but this seems wrong:
>
> (defun f (args &optional history)
> ...
> (setf local-state (make-hash-table))
You should use LET to create a local variable, not assign a global
variable.
> ...
> (f (cdr args) (cons local-state history))
>
>
> Is there a better way to do this in Lisp? Is this something
> continuations do? If there's a resource I should read, I would
> appreciate a pointer.
This doesn't seem like a common programming pattern, so I don't think
there's any built-in mechanism or well-known idiom. There's no standard
way to look things up in a particular stack frame -- you have to provide
your own way to access it.
Your hash-table approach requires you to explicitly copy the value of
each variable into the hash table. Instead, you could use a local
function to access the variables you care about:
(flet ((get-local-state (var)
(ecase var
(var1 var1)
(var2 var2)
...)))
(f (cdr args) (cons #'get-local-state history)))
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
|
|
0
|
|
|
|
Reply
|
barmar (5664)
|
7/10/2007 12:57:29 AM
|
|
Barry Margolin <barmar@alum.mit.edu> writes:
> In article <86d4z2scdu.fsf@deb.lib.aero.>, Ari Krupnik <ari@lib.aero>
> wrote:
>> (defun f (args &optional history)
>> ...
>> (setf local-state (make-hash-table))
>
> You should use LET to create a local variable, not assign a global
> variable.
Point taken.
> Your hash-table approach requires you to explicitly copy the value of
> each variable into the hash table. Instead, you could use a local
> function to access the variables you care about:
>
> (flet ((get-local-state (var)
> (ecase var
> (var1 var1)
> (var2 var2)
> ...)))
> (f (cdr args) (cons #'get-local-state history)))
This looks very powerful, much more useful then the hash table I
imagined. But I'm confused--shouldn't the keys be quoted? Otherwise,
it seems to me the values of the local variables will become the keys,
not their names:
('var1 var1)
('var2 var2)
Ari.
--
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
|
|
0
|
|
|
|
Reply
|
ari (61)
|
7/10/2007 3:13:32 AM
|
|
Ari Krupnik wrote:
> Damien Kick <dkixk@earthlink.net> writes:
>
>> Ari Krupnik wrote:
>>> I'm writing a recursive function, and I find myself asking, how many
>>> invocations of this function are currently on the stack? What's the
>>> value of a local variable 5 invocations down the stack?
>>
>> [...] For example, I'm guessing
>> that something like the following is not really what you're looking
>> for. Or is it?
>>
>> CL-USER 21 > (defun f (n)
>> (when (= n 0)
>> (break))
>> (f (1- n)))
>> F
>
> I was looking for something I could do from inside the function, not
> the REPL. In the example I gave, I can find out how deep the recursion
> is by looking at (length history), for example.
I don't believe that continuations are what you want, either. It
provides one with a means to "capture the stack" but not the tools to
ask questions about it nor to access a binding at any frame in the
stack. I think that CLtL2 environments <http://tinyurl.com/2u4h6v>
provide some level of introspection. Duane Rettig gave a "mega-example"
of using the environment access interface to ask questions about
variable bindings. I think he has also hinted at the possibility of an
implementation using environment access to implement the debugger but my
google-fu fails me at the moment. But if you just want to count the
number of calls to the function, for example, why not just count the
number of calls to the function?
;; There is probably a more elegant way of doing this...
(defmacro defun-with-count (fn args &body forms)
(with-gensyms (count)
` (defun ,fn ,args
(let ((,count 0))
(labels ((,fn ,args
(incf ,count)
(multiple-value-call #'values
(values ((lambda ,args ,@forms) ,@args))
,count)))
(,fn ,@args))))))
It still seems to me that the "how to capture information" depends on
what kind of information and what you want to do with it. Perhaps I'm
missing something, though.
|
|
0
|
|
|
|
Reply
|
dkixk (148)
|
7/10/2007 3:41:51 AM
|
|
In article <86abu5q7c3.fsf@deb.lib.aero.>, Ari Krupnik <ari@lib.aero>
wrote:
> Barry Margolin <barmar@alum.mit.edu> writes:
> > Your hash-table approach requires you to explicitly copy the value of
> > each variable into the hash table. Instead, you could use a local
> > function to access the variables you care about:
> >
> > (flet ((get-local-state (var)
> > (ecase var
> > (var1 var1)
> > (var2 var2)
> > ...)))
> > (f (cdr args) (cons #'get-local-state history)))
>
> This looks very powerful, much more useful then the hash table I
> imagined. But I'm confused--shouldn't the keys be quoted? Otherwise,
> it seems to me the values of the local variables will become the keys,
> not their names:
> ('var1 var1)
> ('var2 var2)
CASE doesn't evaluate that part of the subform, so quoting is not
required. In fact, CASE allows you to put a list of objects there, e.g.
(ecase thing
((thing1 thing2) ...)
((thing3 thing4 thing5) ...)))
Since 'var1 is just shorthand for (quote var1), what you wrote would be
equivalent to:
(ecase var
((quote var1) var1)
((quote var2) var2))
which would cause the value of VAR1 to be returned if VAR's value were
the symbol QUOTE.
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
|
|
0
|
|
|
|
Reply
|
barmar (5664)
|
7/11/2007 4:36:48 AM
|
|
|
6 Replies
24 Views
(page loaded in 0.407 seconds)
|