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",但是mapcar
和length
显然不认为是一个列表。这是因为列表以 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-p
、listify
和 delistify
应该是什么。
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
)。
mapcar
和 length
要求列表参数是一个真正的列表。
要将 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
.
的列表
mapcar
和 length
实际上必须迭代列表并在不正确的列表上阻塞,因为它们不能接受 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)))
此代码的计算结果为 t
(listp '(foo 0 . 0))
这些代码报错:eval: Wrong type argument: listp, 0
(mapcar (lambda (x) x) '(foo 0 . 0))
(length '(foo 0 . 0))
三个都是用同一个"list",但是mapcar
和length
显然不认为是一个列表。这是因为列表以 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-p
、listify
和 delistify
应该是什么。
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
)。
mapcar
和 length
要求列表参数是一个真正的列表。
要将 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
.
mapcar
和 length
实际上必须迭代列表并在不正确的列表上阻塞,因为它们不能接受 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)))