Я действительно запутался с .
обозначениями. Это '(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
)
)
true-list-p
Elisp его нет просто потому, что не было найдено, что оно достаточно полезно для его предоставления. Действительно, я не могу вспомнить, когда в последний раз я хотел проверить правильность списка, поэтому, возможно, если вы дадите нам немного больше информации о вашем сценарии использования, мы поможем решить вашу проблему другим способом.libxml-parse-html-region
и хочу извлечь все<td>
теги.consp
вместо.cddr
списку (чтобы пропустить имя элемента и атрибуты). Как только вы это сделаете, вы должны обнаружить, что все списки являются правильными, и ваша проблема исчезнет. Это также исправит ошибку в вашем коде, когда вы можете спутатьtd
атрибут дляtd
элемента.Ответы:
Это удовлетворяет
listp
, так что в этом смысле это список.listp
просто проверяет, является ли что-то минусом илиnil
(иначе()
), с одной стороны, или чем-то еще, с другой стороны.Правильный список или истинный список (или список , который не пунктирный список или циклический список) является то , что ,
listp
а также имеетnil
в своих последних кордах. То есть, списокXS
является надлежащим , если(cdr (last XS))
естьnil
(и то , как вы отличаете его).Другой способ сделать это - правильный список имеет правильный список в качестве своего cdr . Именно так тип данных (правильный) List определяется на типизированных языках. Это определение универсального и рекурсивного типа: общая часть говорит, что первый аргумент для конструктора непустого списка (часто называемого
cons
BTW) может быть любого типа. Рекурсивная часть говорит, что ее вторым аргументом является экземпляр типа (правильный) List .Да, вы проверяете, является ли данный
listp
список правильным, используя(cdr (last XS))
isnil
. Чтобы проверить, является ли CDR критерия сам по себе правильным списком, вы должны продолжить проверять его CDR, до конца - последние минусы, чтобы увидеть, так ли этоnil
. Вы можете определить предикат для этого следующим образом, если хотите:Хотя циклический список не имеет конца, Emacs (начиная с Emacs 24) достаточно умен для
last
правильной проверки , поэтому этот код работает даже для циклического списка (но только для Emacs 24.1 и новее; для более ранних версий вы получаете «бесконечную» рекурсию). до переполнения стека).Вы можете использовать такие функции, как
length
только в надлежащих списках и других последовательностях. Смотрите также функциюsafe-length
.См. Руководство по Elisp, узел Cons Cells .
Что касается нотации,
(a b)
это просто синтаксический сахар для(a . (b . nil))
- см. Руководство по Elisp, нотация Dotted Pair Notationисточник
(cdr (last XS))
является лиnil
это вялым. Разве нет такой функции, какproper-list-p
?(unless (atom x) (not (cdr (last x))))
Так что вы можете даже позвонить(true-list-p "text")
иnil
не получить ошибку.nil
(то естьlistp
). (Кроме того , FWIW, я не используюunless
илиwhen
для возвращаемого значения я использую.and
,or
Иif
для этого.)