problem with &rest

Discussion of Common Lisp

problem with &rest

Postby 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.
Ajschylos
 
Posts: 18
Joined: Wed Jan 07, 2009 12:44 pm

Re: problem with &rest

Postby 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))))
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: problem with &rest

Postby 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)
dmitry_vk
 
Posts: 96
Joined: Sat Jun 28, 2008 8:01 am
Location: Russia, Kazan

Re: problem with &rest

Postby 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

Re: problem with &rest

Postby 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.
Ajschylos
 
Posts: 18
Joined: Wed Jan 07, 2009 12:44 pm

Re: problem with &rest

Postby 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.
dmitry_vk
 
Posts: 96
Joined: Sat Jun 28, 2008 8:01 am
Location: Russia, Kazan

Re: problem with &rest

Postby 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

Re: problem with &rest

Postby 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.
Ajschylos
 
Posts: 18
Joined: Wed Jan 07, 2009 12:44 pm

Re: problem with &rest

Postby 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)
Tom
 
Posts: 22
Joined: Sat Jun 28, 2008 12:52 pm
Location: Wichita, KS


Return to Common Lisp

Who is online

Users browsing this forum: macrolyte and 4 guests