Emacs 列表不是列表

Emacs list is not a list

此代码的计算结果为 t

(listp '(foo 0 . 0))

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

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

三个都是用同一个"list",但是mapcarlength显然不认为是一个列表。这是因为列表以 0 . 0 而不是 0 0 结尾,虽然我不知道为什么 mapcar 而不是 listp.

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

(以防前一段没说清楚,答错"use (foo 0 0) instead")

我怀疑答案是这样的

(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 应该是什么。

listp returns 非 nil 用于 cons 单元格:

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 要求列表参数是一个真正的列表。

要将 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)))

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

的列表

mapcarlength 实际上必须迭代列表并在不正确的列表上阻塞,因为它们不能接受 cdr 不是cons-cell的东西。

您只需实施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))

在这里,我保留了原始结构,这意味着不正确的列表作为输入给出了不正确的列表作为输出。我不知道这是不是你想要的。如果你想总是 return 正确的列表,那么简单地做:

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