1
votes

I have this example in LISP that removes from every level of a list a given number:

(defun remove_aux (e l)
 (cond 
  ((equal e l) nil)
  ((atom l) (list l))
  (t(list(apply 'append (mapcar #'(lambda (l) (remove_aux e l)) l))))))

 (defun remove_el (e l)
  (car (remove_aux e l)))

So, if it run like this: (remove_el 2 '(1 2 3 ((2 3 2) 4))) => (1 3 ((3) 4))

What I don't exactly understand is how this line works: (t(list(apply 'append (mapcar #'(lambda (l) (sterge_aux e l)) l))))

If I have the line without list and append ((t(mapcar #'(lambda (l) (remove_aux e l)) l))) the result is ((1) NIL (3) ((NIL (3) NIL) (4)))) if it has append but not list ( (t(apply 'append (mapcar #'(lambda (l) (remove_aux e l)) l))) ) then the result is (1 3 3 4) and I don't get why because I did (apply 'append '((1) NIL (3) ((NIL (3) NIL) (4))))) in the Common Lisp console and the result was ((1 3 (NIL (3) NIL) (4))) so I'm really confused. Can somebody explain to me how this all works step by step?

3
this looks ugly. can you please format the code? - Rainer Joswig

3 Answers

1
votes

I've annotated the code below to, I hope, explain what's going on. You're probably getting confused because l is getting redefined within a lambda... so the t line (in your example) has 2 "l"s on it but the first one isn't the same as the second one.

(defun remove_aux (e l)
 (cond 
  ((equal e l) nil) ;if e equals l return nil
  ((atom l) (list l)) ;if l is an atom return a list with just l in it
  (t   ; otherwise...
    (list ;create a list
      (apply 'append ; whose contents are created by appending
                     ; together the lists that come out of this mapcar
                     ; (apply the append method)
        (mapcar #'(lambda (l) ( ; iterate over each of the elements in list l
                                ; the one after the lambda not the one 
                                ; being passed to the lambda. 
                                ; (this is a horrible name choice
                                ; lambda(l-item) would be much better)
                                remove_aux e l
                                ; recursively call this method 
                                ; with e (which was passed in at the start)
                                ; and l which isn't the l passed in,
                                ; but is an entry of it (see why naming's 
                                ; so important?)
                                ; this returns a list
                                ; which will get appended by the append 
                                ; with the results of all the other calls 
                                ; to remove_aux for each item in the outer l
                                )
                  ) l)
      )))))

  (defun remove_el (e l)
    (car (remove_aux e l)
  )
)
1
votes
;; append elements of each list in argument together
(append '(a) '(b) '(c d) '(e))             ; ==> (a b c d e)

;; append elements of each sublist in argument
(apply #'append '((a) (b) (c d) (e)))      ; ==> (a b c d e)

;; apply function on each element of list into new list
(mapcar #'(lambda (x) (+ x 1)) '(1 3 5 6)) ; ==> (2 4 6 7)

So what does the default case do in your function.. Well it applies itself to each sublist of lst and wrap it in a list so if l is '(a y 2 z) and e is 2, well then the result from mapcar is '((a) (y) () (z)) which is then the argument to apply-append which connects the elements together into one list again. When connecting the lists the element that was to be removed is an empty list and it's effectively ignored in the concatenation process.

Since all the lists appended you create in the helper, you could replace the apply-append with (mapcan #'(lambda (l) (remove_aux e l)) l). A more obvious way to do this would be using reduce while a more efficient way might use loop.

0
votes

A procedure that achieve what you want to achieve is essentially like below procedure:

(defun remove-all (e l)"Removes all occurrences of e from a list l."
  (cond
   ((null l) '())
   ((equal e (car l)) (remove-all e (cdr l)))    
   ((not (atom (car l)))
    (cons (remove-all e (car l))
          (remove-all e (cdr l))))
   (t (cons (car l)
            (remove-all e (cdr l))))))
;note: the e is not neccessarily an atom, the l is not necessarily a list of atoms.

The procedure in your question has unnecessarily cluttered pieces, like append, maps etc.

if you recomment below i will explain the algorithm.

have a nice hack.