Estoy realmente confundido con la .
notación. Es '(a . b)
una lista?
(listp '(a . b))
vuelve t
pero cuando quiero saber su longitud (length '(a . b))
da un error Wrong type argument: listp, b
. Lo mismo es para otras funciones como nth,mapcar
etc. todos dan el mismo error
¿Hay alguna función que pueda distinguir entre '(a b)
y '(a . b)
?
Contexto: Encontré este problema cuando quería implementar la versión recursiva de mapcar
. Aquí está mi implementación
(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))
Lo uso para extraer todas las etiquetas específicas del html analizado. Ejemplo de html
analizar
;; 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>
Luego extraigo todo <td>
como
(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
en Elisp simplemente porque no se ha encontrado que sea lo suficientemente útil como para proporcionarlo. De hecho, no recuerdo la última vez que quise probar si una lista era correcta, así que tal vez si nos brinda un poco más de información sobre su caso de uso, podemos ayudarlo a resolver su problema de otra manera.libxml-parse-html-region
y deseo extraer todas las<td>
etiquetas.consp
lugar.cddr
la lista (para omitir el nombre del elemento y los atributos). Una vez que haga eso, debería encontrar que todas las listas son correctas y su problema desaparecerá. También solucionará un error en su código donde puede confundir untd
atributo de untd
elemento.Respuestas:
Satisface
listp
, así que en ese sentido es una lista.listp
solo prueba si algo es una desventaja onil
(aka()
), por un lado, o algo más, por otro lado.Una lista adecuada o una lista verdadera (o una lista que no es una lista punteada o una lista circular) es algo que es
listp
y también tienenil
como su último cdr. Es decir, una listaXS
es adecuada si(cdr (last XS))
es asínil
(y así es como la distingue).Otra forma de decir esto es que una lista adecuada tiene una lista adecuada como su cdr . Esta es la forma en que la Lista de tipos de datos (adecuada) se define en los idiomas escritos. Es una definición de tipo genérico y recursivo: la parte genérica dice que el primer argumento para el constructor de lista no vacía (a menudo llamado
cons
, por cierto) puede ser de cualquier tipo. La parte recursiva dice que su segundo argumento es una instancia de tipo (apropiado) Lista .Sí, verifica si un dado
listp
es una lista adecuada usando(cdr (last XS))
isnil
. Para verificar si el cdr del bicho es en sí mismo una lista adecuada, debe continuar verificando su cdr, hasta el final, los últimos inconvenientes, para ver si es asínil
. Puede definir un predicado para esto de la siguiente manera, si desea:Aunque una lista circular no tiene fin, Emacs (comenzando con Emacs 24) es lo suficientemente inteligente como para verificar
last
correctamente, por lo que este código funciona incluso para una lista circular (pero solo para Emacs 24.1 y posterior; para versiones anteriores obtienes una recursión "infinita" hasta que la pila se desborde).Puede usar funciones como
length
solo en listas apropiadas y otras secuencias. Ver también funciónsafe-length
.Consulte el manual de Elisp, celdas de cons . De nodo .
En cuanto a la notación,
(a b)
es solo azúcar sintáctica para(a . (b . nil))
- vea el manual de Elisp, notación de pares de puntos de nodofuente
(cdr (last XS))
esnil
es crumblesome. ¿No hay una función comoproper-list-p
?(unless (atom x) (not (cdr (last x))))
Para que puedas llamar(true-list-p "text")
ynil
no obtener un error.nil
(es decir,listp
). (Además, pedía algo, yo no usounless
owhen
por su valor de retorno que utilizo.and
,or
Y,if
por eso.)