Emacs列表不是列表

时间:2015-10-06 20:59:20

标签: emacs elisp

此代码的评估结果为t

(listp '(foo 0 . 0))

这些代码会出错:eval: Wrong type argument: listp, 0

(mapcar (lambda (x) x) '(foo 0 . 0))
(length '(foo 0 . 0))

这三个人都使用相同的“列表”,但mapcarlength显然不认为它是一个列表。这是因为列表以0 . 0而不是0 0结尾,但我不知道为什么这会对mapcar产生影响,而不是listp

有没有办法修改mapcar表达式以接受常规列表,如(foo 0 0)和这些cons样式列表(foo 0 . 0)?在实际的应用程序中,我的输入有两种类型的列表(例如("a" (b 0 . 0) (c 0 . 0)),lambda是一个递归函数,如果它的参数是一个列表,则调用mapcar

(如果前一段不清楚,则“使用(foo 0 0)代替”是错误的。)

我怀疑答案是

(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
   ))

但是,我不知道not-actually-a-list-plistifydelistify应该是什么。

2 个答案:

答案 0 :(得分:4)

listp返回T的原因是因为它只检查参数是nil还是cons-cell。 正确列表nil或所有cdr满足listp的列表。

mapcarlength实际上必须迭代列表并阻塞不正确的列表,因为他们无法将cdr视为不属于缺点的内容。

您只需实施mapcar-dot即可解决问题。例如,这是一个递归方法:

(defun mapcar-dot (f list)
  (typecase list
    (null nil)
    (cons (cons (funcall f (car list))
                (mapcar-dot f (cdr list))))
    (t (funcall f list))))

实施例

(list (mapcar-dot #'1+ '(1 2 3 4))
      (mapcar-dot #'1+ '(1 2 3 . 4)))
=> ((2 3 4 5) (2 3 4 . 5))

在这里,我保留了原始结构,这意味着不正确的列表作为输入会将不正确的列表作为输出。我不知道这是不是你想要的。如果您想要始终返回正确的列表,那么只需执行以下操作:

(defun mapcar-dot* (f list)
  (loop for (a . b) on list
        collect (funcall f a)
        unless (listp b)
          collect (funcall f b)))

答案 1 :(得分:2)

listp为cons小区返回非nil

listp is a built-in function in ‘C source code’.

(listp OBJECT)

Return t if OBJECT is a list, that is, a cons cell or nil.
Otherwise, return nil.

listp不检查真正的列表(即,使用cdr的最后一个cons小区nil)。

mapcarlength要求list参数为真实列表。

要将mapcar应用于可能不是正确列表的列表,您可以执行以下操作:

(defun my-map (fn conses)
  "Like `mapcar', but for a dotted list also."
  (let ((res  ()))
    (while (consp conses)
      (push (funcall fn (car conses)) res)
      (setq conses  (cdr conses)))
    (when conses (push (funcall fn conses) res))
    (nreverse res)))