This code evaluates to t
(listp '(foo 0 . 0))
These code gives an error: eval: Wrong type argument: listp, 0
(mapcar (lambda (x) x) '(foo 0 . 0))
(length '(foo 0 . 0))
All three are using the same "list", but mapcar
and length
clearly do not think that it is a list. This is because the list ends with a 0 . 0
rather than 0 0
, although I do not know why that makes a difference to mapcar
but not listp
.
Is there a way to modify the mapcar expression to accept both regular lists like (foo 0 0)
and these cons-style lists (foo 0 . 0)
? In the actually application, my input has both types of lists (e.g., ("a" (b 0 . 0) (c 0 . 0))
and the lambda is a recursive function that calls mapcar
if its argument is a list.
(In case the previous paragraph was not clear, the answer "use (foo 0 0)
instead" is wrong.)
I suspect the answer is something like
(defun my-func (x)
(if (consp x)
(if (not-actually-a-list-p x)
(delistify (mapcar #'myfunc (listify x)))
(mapcar #'myfunc input))
; process the individual atoms
))
However, I do not know what not-actually-a-list-p
, listify
and delistify
should be.
The reason listp
returns T
is because it only checks whether the argument is either nil
or a cons-cell. A proper list is either nil
or one where all cdr
satisfy listp
.
mapcar
and length
actually have to iterate the list and choke on improper lists, because they cannot take the cdr
of something not being a cons-cell.
You only need to implement mapcar-dot
to solve your problem. For example, here is a recursive approach:
(defun mapcar-dot (f list)
(typecase list
(null nil)
(cons (cons (funcall f (car list))
(mapcar-dot f (cdr list))))
(t (funcall f list))))
Example
(list (mapcar-dot #'1+ '(1 2 3 4))
(mapcar-dot #'1+ '(1 2 3 . 4)))
=> ((2 3 4 5) (2 3 4 . 5))
Here, I preserve the original structure, meaning that improper lists as inputs give improper lists as outputs. I don't know if this is what you want. In case you want to always return proper lists, then simply do:
(defun mapcar-dot* (f list)
(loop for (a . b) on list
collect (funcall f a)
unless (listp b)
collect (funcall f b)))