Je suis vraiment confus avec la .
notation. Est-ce '(a . b)
une liste?
(listp '(a . b))
retourne t
mais quand je veux savoir sa longueur (length '(a . b))
donne une erreur Wrong type argument: listp, b
. La même chose est pour les autres fonctions comme nth,mapcar
etc., elles donnent toutes la même erreur
Y a-t-il une fonction que je peux distinguer entre '(a b)
et '(a . b)
?
Contexte: J'ai rencontré ce problème lorsque j'ai voulu implémenter une version récursive de mapcar
. Voici ma mise en œuvre
(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))
Je l'utilise pour extraire toutes les balises spécifiques du html analysé. Exemple d' html
analyse
;; 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>
Ensuite, j'extrait tout <td>
comme
(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 a pas dans Elisp simplement parce qu'il n'a pas été jugé suffisamment utile pour le fournir. En effet, je ne me souviens pas de la dernière fois que j'ai voulu tester si une liste était correcte, alors peut-être que si vous nous donnez un peu plus d'informations sur votre cas d'utilisation, nous pouvons vous aider à résoudre votre problème d'une autre manière.libxml-parse-html-region
et que je veux extraire toutes les<td>
balises.consp
place.cddr
la liste (pour ignorer le nom de l'élément et les attributs). Une fois que vous avez fait cela, vous devriez constater que toutes les listes sont correctes et votre problème disparaîtra. Il corrigera également un bogue dans votre code où vous pouvez confondre untd
attribut pour untd
élément.Réponses:
Il satisfait
listp
, donc en ce sens, c'est une liste.listp
teste simplement si quelque chose est contre ounil
(aka()
), d'une part, ou autre chose, d'autre part.Une liste correcte ou une liste vraie (ou une liste qui n'est pas une liste en pointillés ou une liste circulaire) est quelque chose qui est
listp
et a égalementnil
comme dernier cdr. Autrement dit, une listeXS
est appropriée si(cdr (last XS))
estnil
(et c'est ainsi que vous la distinguez).Une autre façon de dire ceci est qu'une liste appropriée a une liste appropriée comme son cdr . C'est ainsi que le type de données (approprié) List est défini dans les langues tapées. Il s'agit d'une définition de type générique et récursive: la partie générique indique que le premier argument du constructeur de liste non vide (souvent appelé
cons
BTW) peut être de n'importe quel type. La partie récursive dit que son deuxième argument est une instance de type (propre) List .Oui, vous vérifiez si une donnée
listp
est une liste appropriée en utilisant(cdr (last XS))
isnil
. Afin de vérifier si le cdr de la créature est lui-même une liste appropriée, vous devez continuer à vérifier son cdr, jusqu'à la fin - le dernier inconvénient, pour voir s'il l'estnil
. Vous pouvez définir un prédicat pour cela comme suit, si vous le souhaitez:Bien qu'une liste circulaire n'ait pas de fin, Emacs (commençant par Emacs 24) est suffisamment intelligent pour vérifier
last
correctement, donc ce code fonctionne même pour une liste circulaire (mais uniquement pour Emacs 24.1 et versions ultérieures; pour les versions antérieures, vous obtenez une récursion "infinie" jusqu'au débordement de la pile).Vous pouvez utiliser des fonctions telles que
length
uniquement sur des listes appropriées et d'autres séquences. Voir aussi fonctionsafe-length
.Voir le manuel Elisp, node Cons Cells .
Quant à la notation,
(a b)
c'est juste du sucre syntaxique pour(a . (b . nil))
- voir le manuel Elisp, noeud Notation par paire pointéela source
(cdr (last XS))
estnil
est crumblesome. N'y a-t-il pas une fonction commeproper-list-p
?(unless (atom x) (not (cdr (last x))))
vous puissiez même appeler(true-list-p "text")
etnil
ne pas avoir d'erreur.nil
(c.-àlistp
-d.). ( De plus, FWIW, je ne pas utiliserunless
ouwhen
pour leur valeur de retour , je l' utilise.and
,or
Etif
pour cela.)