Discussion of Common Lisp
-
Ajschylos
- Posts: 18
- Joined: Wed Jan 07, 2009 12:44 pm
Post
by Ajschylos » Sun Feb 08, 2009 12:33 pm
Hi,
I need a function which appends either lists and atoms into one list.
I've tried many variations on something like this:
Code: Select all
(defun app-sym ( &rest lst)
(if (null lst) nil
(cond
((atom (car lst)) (append (list (car lst)) (app-sym (cdr lst))))
((listp (car lst)) (append (car lst) (app-sym (cdr lst)))))))
but it doesn't even compile or work.
Can anybody explain to me what are the limits of using &rest within body of function?
i found no answer in "Common Lisp HyperSpec".
I am using LispWorks.
Should I write a macro ??? Brrr.. it is still to difficult for me
A.
-
ramarren
- Posts: 613
- Joined: Sun Jun 29, 2008 4:02 am
- Location: Warsaw, Poland
-
Contact:
Post
by ramarren » Sun Feb 08, 2009 1:43 pm
What do you mean by "limits"? The variable is bound to the list of remaining arguments, and within the body of a function it acts as any other variable. In any case, I would suggest iterative solution, maybe like this (if I understand what you want correctly):
Code: Select all
(defun app-sym (&rest arguments)
(loop for a in arguments
appending (if (listp a)
a
(list a))))
-
dmitry_vk
- Posts: 96
- Joined: Sat Jun 28, 2008 8:01 am
- Location: Russia, Kazan
-
Contact:
Post
by dmitry_vk » Sun Feb 08, 2009 1:47 pm
Your function does not work because of infinite recursion. The last call to the function is (app-sym nil), and the lst == '(nil). But (nill '(nil)) == NIL, so recursion is entered again.
Anyway, the short and more approachable way is to write it like this:
Code: Select all
(defun ensure-list (thing)
(if (listp thing)
thing
(list thing)))
(defun app-sym (&rest args)
(mapcan #'ensure-list args))
(app-sym 1 2 3) => (1 2 3)
(app-sym 1 '(2 abc 123) 4) => (1 2 ABC 123 4)
-
Ajschylos
- Posts: 18
- Joined: Wed Jan 07, 2009 12:44 pm
Post
by Ajschylos » Sun Feb 08, 2009 10:26 pm
Hi Ramaren, you seem to understand perfectly well, your solution works like I want,
but I am interested in recursive solution, and I would like to know why my function doesn't work.
Thanks anyway, A.
-
Ajschylos
- Posts: 18
- Joined: Wed Jan 07, 2009 12:44 pm
Post
by Ajschylos » Sun Feb 08, 2009 10:33 pm
Dmitry, Your solution looks cute, and it works.
I see that I've run into an infinite loop, but still do not understand why.
The test (if (null lst) nil "else" ... do sth.) should work if the parameter after &rest is an ordinary list as suggests Ramaren, but it does not.
-
dmitry_vk
- Posts: 96
- Joined: Sat Jun 28, 2008 8:01 am
- Location: Russia, Kazan
-
Contact:
Post
by dmitry_vk » Sun Feb 08, 2009 10:53 pm
Ajschylos wrote:I see that I've run into an infinite loop, but still do not understand why.
The test (if (null lst) nil "else" ... do sth.) should work if the parameter after &rest is an ordinary list as suggests Ramaren, but it does not.
The lst after the supposedly-last recursive call is the ordinary list that would contain a single NIL: (NIL). So (null lst) never returns false. lst is the list of arguments. You always call the app-sym with some argument (but the argument may be NIL), and the arguments list is not empty (but may contain NILs) so lst is not null.
-
Ajschylos
- Posts: 18
- Joined: Wed Jan 07, 2009 12:44 pm
Post
by Ajschylos » Mon Feb 09, 2009 2:58 am
Ok. dmitri, now I understand my mistake.
Thanks.
A.
-
Ajschylos
- Posts: 18
- Joined: Wed Jan 07, 2009 12:44 pm
Post
by Ajschylos » Mon Feb 09, 2009 3:56 am
Now my function works:
Code: Select all
(defun app-sym (&rest l)
(labels (( a-s (x)
(let ((el (car x)))
(if (null x) nil
(cond ((listp el) (append el (a-s (cdr x))))
((atom el) (append (list el) (a-s (cdr x))))
(T nil))))))
(a-s l)))
Surely it's not so efficient as yours, but it let me train some recursion.
Thanks for help.
-
Tom
- Posts: 22
- Joined: Sat Jun 28, 2008 12:52 pm
- Location: Wichita, KS
-
Contact:
Post
by Tom » Thu Feb 12, 2009 1:58 pm
A slightly different recursive solution. This one will handle any level of nesting in the lists.
Code: Select all
(defun app-sym (&rest lst)
"Flatten the lists."
(let ((item (first lst)))
(cond
((null item) nil)
((atom item) (cons item (app-sym (rest lst))))
((listp item)
(append (app-sym (first item))
(app-sym (rest item))
(app-sym (rest lst)))))))
CL-USER> (app-sym '((a b c) d (e f g) h ((i j) (k l))))
(A B C D E F G H I J K L)