Search code examples
lispcommon-lispclisp

Flattening lists (while removing 'nil' and keeping atoms after " . ") in lisp


I want to create a function that would flatten a list and remove all potential nil inside.

Expected behavior, example 1:

(myfunc '(a (b (c) (d)) (e f) (g (h)) nil)) => (a b c d e f g h)

Expected behavior, example 2:

(myfunc '(a . d)) => (a d) 

my function so far:

(defun myfunc (l)
   (cond
      ((atom l) nil)
         ((and (atom (car l)) (not (equal (car l) nil))) (cons (car l) (myfunc (cdr l))))
         (t (append (myfunc (car l)) (myfunc (cdr l))))))

My function works as expected for the first example, but not the second. I get:

(myfunc '(a . d)) => (a) 
  1. Why doesn't it keep that d?

  2. Is there a way to fix it?


Solution

  • Perhaps you should think about what the flatten function should do, in plain English:

    1. Base case: If flattening nil, return an empty list.
    2. Base case: If flattening single atoms, return a list containing just that.
    3. Recursive case: If flattening pairs, return a list appending the flattening of its car with the flattening of its cdr.

    Here's how I'd implement the description I just gave:

    (defun flatten (x)
      (cond ((null x) x)
            ((atom x) (list x))
            (t (nconc (flatten (car x)) (flatten (cdr x))))))