Reputation: 21261
(EDIT: I'm not going to worry about TCO yet)
I'm (finally getting around to) learning Lisp. I'm trying to write my own (naive-ish) function to flatten a list. I'm starting with the simpler cases and will build it up to handle more complex cases if it doesn't work. Unfortunately right now, I'm getting an infinite loop and can't quite figure out why.
I also don't know how to use any debugging methods in lisp so if you could point me in that direction, too I'd appreciate it.
(defun flattenizer (lst)
(if (listp (car lst))
(flattenizer (car lst))
(if (null lst)
nil
(cons (car lst) (flattenizer (cdr lst))))))
final code:
(defun flattenizer (lst)
(cond
((null lst) nil)
( (consp (car lst))
(nconc (flattenizer (car lst)) (flattenizer (cdr lst)) ))
(T (cons (car lst) (flattenizer (cdr lst))))))
tests:
* (flattenizer '((1 2) (3 4)))
(1 2 3 4)
* (flattenizer '(1 (2 3) (4 5)))
(1 2 3 4 5)
* (flattenizer '((1 2) 3 (4 5) 6))
(1 2 3 4 5 6)
* (flattenizer '(1 2 3 4))
(1 2 3 4)
Upvotes: 4
Views: 432
Reputation: 114609
NIL
is somewhat "strange" in Common Lisp for a mix of practical and historical reasons. For example:
NIL
is a symbol: (symbolp NIL) ==> T
NIL
is a list: (listp NIL) ==> T
NIL
is not a cons cell: (consp NIL) ==> NIL
car
/cdr
of it anyway: (car NIL) ==> NIL
and (cdr NIL) ==> NIL
In your code calling recursively for (car x)
when (listp (car x))
is causing infinite recursion because NIL
is a list and its car
is itself.
Upvotes: 5
Reputation: 71119
(listp NIL)
returns T
, and so does (listp (car NIL))
, so when you hit the end-of-list and recurse on NIL
, looping happens.
You need to change the order of your tests, testing for the (null lst)
first, to avoid the looping. Better re-write it with cond
for that. It's easier to change the ordering of tests, with cond
.
Then you'll notice that for some reason you only flatten the first element in your argument list, ever. What about (3 4)
in ((1 2) (3 4))
etc.? We should really somehow combine the results of flattening the car
with the results of flattening the cdr
.
If the result of flattening a list is a list, then we will need to combine the two resulting lists. Also, since we will be combining lists, if we encounter an atom we will have to produce a list, as the result of flattening that atom.
Upvotes: 6
Reputation: 139411
Debugging using SBCL.
Tell SBCL you want debug:
* (proclaim '(optimize (debug 3)))
Your code:
* (defun flattenizer (lst)
(if (listp (car lst))
(flattenizer (car lst))
(if (null lst)
nil
(cons (car lst) (flattenizer (cdr lst))))))
FLATTENIZER
Stepping it with STEP
* (step (flattenizer '(1 (2 3) 4)))
; Evaluating call:
; (FLATTENIZER '(1 (2 3) 4))
; With arguments:
; (1 (2 3) 4)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; ((2 3) 4)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; (2 3)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; (3)
next step
1] step
; Evaluating call:
; (FLATTENIZER (CDR LST))
; With arguments:
; NIL
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; NIL
next step
1] step
; Evaluating call:
; (FLATTENIZER (CAR LST))
; With arguments:
; NIL
Looks like you are in a loop now.
Getting back to the toplevel.
1] top
*
Now check your source code.
Upvotes: 4