'(a。b)确实是列表吗?


15

我对.表示法感到困惑。是'(a . b)清单吗?

(listp '(a . b))返回,t但是当我想知道它的长度(length '(a . b))给出一个错误时Wrong type argument: listp, b。其他功能也一样,nth,mapcar它们都给出相同的错误

是否可以区分'(a b)和的任何功能'(a . b)


上下文:我想实现的递归版本时遇到此问题mapcar。这是我的实现

(defun true-listp (object)
"Return non-`nil' if OBJECT is a true list."
(and (listp object)  (null (cdr (last object)))))

(defun recursive-mapcar (func list)
"Evaluates func on elements of the list, then on elements of elements  of the list and so forth." 
(let ((output nil))
(flet ((comp (a b) nil)
       (call-fun-and-save (x) (add-to-list 'output (funcall func x) t 'comp))
       (recursion (l)
                  (mapcar
                   (lambda (x)
                     (call-fun-and-save x)
                     (if (and (true-listp x))  ;; HERE I use true-listp, testing for list or cons is not sufficient
                         (recursion x)))
                    l)))
   (recursion list))
  output))

我用它从解析的html中提取所有特定的标签。html解析示例

;; buffer 'html'
<html>
<body>
<table style="width:100%">
  <tr>  <td>Jill</td>  <td>Smith</td>  <td>50</td> </tr>
  <tr>  <td>Eve</td>   <td>Jackson</td>   <td>94</td> </tr>
</table>
</body>
</html>

然后我将所有内容提取<td>

(with-current-buffer (get-buffer "html")
  (let ((data (libxml-parse-html-region (point-max) (point-min))))

    ;; gat only <td> tags
    (-non-nil
     (recursive-mapcar
      (lambda(x) (and (consp x) (equal 'td (car x)) x))
      data))
    data
    )
  )

1
true-list-pElisp 中没有任何功能,只是因为尚未发现它足以提供它。的确,我不记得上一次我想测试列表是否正确,因此,如果您向我们提供有关用例的更多信息,我们可能会以另一种方式帮助您解决问题。
Stefan

@Stefan简而言之,我想实现递归mapcar,我在给定列表的元素上,然后在列表元素的元素上,然后在列表元素的元素上等等,评估给定函数。所以我需要知道一个元素是否为真实列表。
汤姆

例如,当我使用解析html libxml-parse-html-region并要提取所有<td>标签时,它很有用。
汤姆(Tom)

您能否向我们展示一个具体的示例,在该示例中,您可能会得到正确的列表,不正确的列表或其他内容,并且需要以不同的方式处理这三种情况?在大多数情况下,我不得不处理“适当”和“不适当”的情况,直到我们发现不正确的尾巴为止,然后再进行共享,因此您无需再次测试它是否正确:只需测试是否它consp代替。
Stefan 2013年

1
libxml不仅返回列表列表。每个表示XML元素的列表都具有以下形式(符号属性。contents)。因此,您的代码不应将mapcar递归地应用于列表的所有元素,而只能应用于cddr列表的(以跳过元素名称和属性)。完成此操作后,您将发现所有列表均正确,问题将消失。它还将修复代码中的错误,使您可能混淆元素的td属性td
Stefan 2016年

Answers:


22

它满足listp,因此从某种意义上讲,它是一个列表。 listp只是测试一方面是负面因素还是nil(aka ()),另一方面是其他因素。

一个适当的清单真实的目录(或列表不是一个点列表或圆形列表)的东西是listp,也有nil作为其最后的CDR。也就是说,列表XS正确的(如果(cdr (last XS))是)nil(这就是您区分列表的方式)。

另一种表达方式是,适当的列表将其适当的列表作为其cdr。这是用打字语言定义数据类型(适当)列表的方式。这是一个通用的递归类型定义:通用部分说,非空列表构造函数的第一个参数(通常称为consBTW)可以是任何类型。递归部分说它的第二个参数是List类型的一个实例。

是的,您可以listp使用(cdr (last XS))is 检查给定的列表是否正确nil。为了检查小动物的cdr本身是否是正确的列表,您必须继续检查它的cdr,直到最后一个缺点,看看它是否为nil。如果要执行以下操作,则可以为此定义一个谓词:

(defun true-listp (object)
  "Return non-`nil' if OBJECT is a true list."
  (and (listp object)  (null (cdr (last object)))))

尽管循环列表没有止境,但是Emacs(从Emacs 24开始)足够聪明,可以last正确地进行检查,因此即使对于循环列表,此代码也适用(但仅适用于Emacs 24.1和更高版本;对于较早的版本,您可以获得“无限”的递归)直到堆栈溢出)。

您可以使用诸如length仅在正确列表和其他序列上的功能。另请参见功能safe-length

请参见Elisp手册,节点Cons Cells

至于表示法,(a b)仅仅是语法上的糖(a . (b . nil))-参见Elisp手册,节点点对表示法


检查正确列表的最佳实践是什么?检查是否(cdr (last XS))nil为crumblesome。是否没有类似的功能proper-list-p
汤姆

@tom:那是必需的,或者是等效的-您必须检查最后一个cons单元。我现在在答案中添加了更多有关此的内容。
德鲁

@Drew我会将函数的主体更改为,(unless (atom x) (not (cdr (last x))))因此您甚至可以调用(true-list-p "text")并且nil不会出错。
汤姆

@tom:对;谢谢。实际上,应该首先对其进行测试以确保它是一个缺点或nil(即listp)。(另外,FWIW,我不使用unlesswhen为他们的返回值我用。andor以及if为。)
德鲁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.