Stepping through code?

Discussion of Common Lisp
speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

Stepping through code?

Post by speech impediment » Thu Feb 25, 2010 6:57 am

I have tried the step function on Steel Bank Common Lisp, and I am not sure if I am using it properly. Their manual didn't really explain about step well to a newbie like me. I am trying to learn more about step using a recursive function (Fibonacci), but it just gives me the result without stepping through anything. Here is what it looks like to me:

Code: Select all

* (step (fibo 5))
; Evaluating call:
;   (FIBO 5)
; With arguments:
;   5

1] 
When I type next, it just gives me the answer: 8. I tried Clozure as well, but nothing there either...

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Stepping through code?

Post by ramarren » Thu Feb 25, 2010 7:11 am

Works for me:

Code: Select all

* (defun test-step () (declare (optimize (debug 3)))(print 'a)(print 'b)(print 'c))

TEST-STEP
* (step (test-step))
; Evaluating call:  
;   (TEST-STEP)     
; With arguments:   
;                   

1] :step
; Evaluating call:
;   (PRINT 'A)
; With arguments:
;   A

1] :next

; Evaluating call:
;   (PRINT 'B)
; With arguments:
;   B
A
1] :next

; Evaluating call:
;   (PRINT 'C)
; With arguments:
;   C
B
1] :next

; (TEST-STEP) => C
C
C
Did you actually enabled stepping? Also note that stepping into the form is done with 'step' command, not 'next'. Macro (step ...) macro can contain multiple forms, and top level 'next' will step over those forms.

smithzv
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

Re: Stepping through code?

Post by smithzv » Thu Feb 25, 2010 11:42 am

I think a key thing here is the optimization settings. For certain settings of debug, you will not include the instrumentation necessary for stepping through your code. As it turns out, the SBCL default optimization settings don't allow for stepping (this was a surprise to me, did this change from the way it was about a year ago?). So you need the set debug higher than speed, space, and compilation-speed (http://www.sbcl.org/manual/Debugger-Pol ... cy-Control):
SBCL manual wrote:> (max speed space compilation-speed)
If debug is greater than all of speed, space and compilation-speed the code will be steppable (see Single Stepping).

speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

Re: Stepping through code?

Post by speech impediment » Fri Feb 26, 2010 11:08 am

Aha. I missed this bit:

Code: Select all

(declare (optimize (debug 3)))
I did not put that in my function. I don't suppose there is a way to avoid putting this in each and every function is there? It seems to single step fine now, however, I think when it evaluates a tail recursive call, it seems to just compress the recursion and it doesn't cycle back to the top. So is this setting the most detailed stepping?

Thanks y'all.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Stepping through code?

Post by ramarren » Fri Feb 26, 2010 11:29 am

speech impediment wrote:Aha. I missed this bit:
It is mentioned in the first paragraph of the manual. Reading documentation is usually more productive than guessing. You can set compiler policy using top level declaim. Note that as the Hyperspec says, it is unspecified if delaimations are file-specific or global, but for debugging you can just do a DECLAIM from the REPL before compilation.
speech impediment wrote:I think when it evaluates a tail recursive call, it seems to just compress the recursion and it doesn't cycle back to the top
In tail recursion there is not top to cycle back to by definition.

smithzv
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

Re: Stepping through code?

Post by smithzv » Fri Feb 26, 2010 11:41 am

speech impediment wrote:I don't suppose there is a way to avoid putting this in each and every function is there?
You can declaim it before any functions you want to step through.

Code: Select all

(declaim (optimize (debug 3)))
speech impediment wrote:I think when it evaluates a tail recursive call, it seems to just compress the recursion and it doesn't cycle back to the top
Not sure what you mean so I will cast a few lines: setting debug setting high often times disables tail call optimization, and at least naive a implementation of Fibonacci doesn't have tail calls anyway, but maybe you are using something more sophisticated? Be that as it may, when I tried this, stepping into the lower fibo calls acted as I expected, cycling back to the top, at least in SBCL. So that it weird... Why don't you post a repl transcript from a fresh image to demonstrate.
Ramarren wrote:In tail recursion there is not top to cycle back to by definition.
Really? It is still calling the function recursively, it just isn't returning to that frame. Am I wrong?
speech impediment wrote:So is this setting the most detailed stepping?
The manual does allude to different levels of stepability, but the debug policy page seems to suggest that (> debug (max speed space compilation-speed)) is the only factor. So unless there are some SBCL internals people here, you could drop by #lisp on irc.freenode.net and ask them there.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Stepping through code?

Post by ramarren » Fri Feb 26, 2010 12:06 pm

smithzv wrote:Really? It is still calling the function recursively, it just isn't returning to that frame. Am I wrong?
I might not get what is the 'top' here. I interpreted is a something to do with a higher stack frame, which contains nothing. Obviously execution jumps to the top of the function with new arguments, but that does happen with SBCL stepper.

Code: Select all

* (defun recur (list) (declare (optimize (debug 3))) (print (car list))(if list (recur (cdr list))))                                                                                      
STYLE-WARNING: redefining RECUR in DEFUN                                                     

RECUR
* (step (recur '(1 2 3)))
; Evaluating call:       
;   (RECUR '(1 2 3))     
; With arguments:        
;   (1 2 3)              

1] step
; Evaluating call:
;   (PRINT (CAR LIST))
; With arguments:     
;   1                 

1] next

; Evaluating call:
;   (RECUR (CDR LIST))
; With arguments:     
;   (2 3)             
1                     
1] step
; Evaluating call:
;   (PRINT (CAR LIST))
; With arguments:     
;   2                 

1] next

; Evaluating call:
;   (RECUR (CDR LIST))
; With arguments:     
;   (3)               
2                     
1] step
; Evaluating call:
;   (PRINT (CAR LIST))
; With arguments:
;   3

1] next

; Evaluating call:
;   (RECUR (CDR LIST))
; With arguments:
;   NIL
3
1] step
; Evaluating call:
;   (PRINT (CAR LIST))
; With arguments:
;   NIL

1] next

; (RECUR (CDR LIST)) => NIL
; (RECUR (CDR LIST)) => NIL
; (RECUR (CDR LIST)) => NIL
; (RECUR '(1 2 3)) => NIL
NIL
NIL

speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

Re: Stepping through code?

Post by speech impediment » Fri Feb 26, 2010 5:11 pm

I am sorry that I appear to not have read the manual, but it was hard to decipher where and when to type the keywords like :step and :next and (declare (optimize (debug 3))). I went through the SBCL manual and the hyperspec for about 30 minutes, but I didn't find anything as clear as what Rammaren simply showed. I might be misusing terminology when I am talking about tail recursion... I just assumed that with multiple recursion like the simple Fibonacci function, it is still considered a tail recursive function. When I say cycle back to the top, I just meant to say to start the next cycle of recursion. There's probably a technically correct way to say this... :P
You can declaim it before any functions you want to step through.
I am not sure what you mean, but after perusing the hyperspec, I presume you are talking about having (declare (optimize (debug 3))) outside of the function and replace declare with declaim. Like this:

Code: Select all

(declaim (optimize (debug 3)))

(defun test-step () (print 'a)(print 'b)(print 'c))
I tested it with another function without having to insert a declare expression again, so it seems to work...

Once again, I am grateful to you folks for being patient and so helpful.

Code: Select all

(defun fibo (n) (declare (optimize (debug 3)))
	(cond ((equal n 0) 1)
			((equal n 1) 1)
			(t (+ (fibo (- n 1)) (fibo (- n 2))))))
* (step (fibo 5))
; Evaluating call:
;   (FIBO 5)
; With arguments:
;   5

1] :step
; Evaluating call:
;   (EQUAL N 0)
; With arguments:
;   5
;   0

1] :next
; Evaluating call:
;   (EQUAL N 1)
; With arguments:
;   5
;   1

1] :next
; Evaluating call:
;   (- N 1)
; With unknown arguments

0] :next
; Evaluating call:
;   (FIBO (- N 1))
; With arguments:
;   4

1] :next
; Evaluating call:
;   (- N 2)
; With unknown arguments

0] :next
; Evaluating call:
;   (FIBO (- N 2))
; With arguments:
;   3

1] :next
; Evaluating call:
;   (+ (FIBO (- N 1)) (FIBO (- N 2)))
; With unknown arguments

0] :next
; (FIBO 5) => 8
8
* 
So if you scroll all the way down, once it creates the two branches, the result is given and there are no more branches to step through. It doesn't even step through the process of addition.
Last edited by speech impediment on Wed Apr 23, 2014 10:33 pm, edited 1 time in total.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Stepping through code?

Post by ramarren » Sat Feb 27, 2010 1:26 am

speech impediment wrote:So if you scroll all the way down, once it creates the two branches, the result is given and there are no more branches to step through.
I explained it in very first reply: :next evaluates the expression as the whole and goes to the next one, :step steps into it. You have to use :step to step into recursive calls. Or any calls.
speech impediment wrote:It doesn't even step through the process of addition.
Addition is a primitive operation and doesn't have anything to step through. Well, I suppose there is type dispatch and so, but why would you want to step SBCL internals?

The arguments are separated and stepped through before, it can be seen in the stepper output you posted.

speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

Re: Stepping through code?

Post by speech impediment » Sat Feb 27, 2010 10:31 am

I explained it in very first reply: :next evaluates the expression as the whole and goes to the next one, :step steps into it. You have to use :step to step into recursive calls. Or any calls.
This is clear now. :oops:
Addition is a primitive operation and doesn't have anything to step through. Well, I suppose there is type dispatch and so, but why would you want to step SBCL internals?
Well, I was learning about order of evaluation; Normal order vs. Applicative order. How side effects effects does matter in order of evaluation, etc. So I was thinking if I miscalculate order of evaluation and get an outcome I did not understand, it would be helpful. Also, there might be situations where I was dumb enough to mix up something like this: (/ (+ 1 1)(/ 3 3)) and expect that I was doing this: 1/2. However, I do see you point now that I was able to step through my code. Forgive my ignorance again, but I can't seem to find type dispatch in the hyperspec. What is that?

Post Reply