Ich bin wirklich verwirrt mit der .
Notation. Ist '(a . b)
eine Liste?
(listp '(a . b))
kehrt t
aber zurück wenn ich wissen will wie lang es ist (length '(a . b))
gibt es einen fehler Wrong type argument: listp, b
. Das Gleiche gilt für andere Funktionen wie nth,mapcar
usw. Sie geben alle den gleichen Fehler aus
Gibt es eine Funktion, die ich zwischen '(a b)
und unterscheiden kann '(a . b)
?
Kontext: Ich bin auf dieses Problem gestoßen, als ich die rekursive Version von implementieren wollte mapcar
. Hier ist meine Implementierung
(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))
Ich benutze dieses, um alle spezifischen Umbauten von analysiertem HTML zu extrahieren. Beispiel für html
das Parsen
;; 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>
Dann extrahiere ich alles <td>
als
(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
in Elisp, nur weil es nicht nützlich genug ist, um es bereitzustellen. In der Tat kann ich mich nicht erinnern, wann ich das letzte Mal testen wollte, ob eine Liste korrekt war. Wenn Sie uns also ein bisschen mehr Informationen zu Ihrem Anwendungsfall geben, können wir Ihnen helfen, Ihr Problem auf andere Weise zu lösen.libxml-parse-html-region
und alle<td>
Tags extrahieren möchte .consp
stattdessen.cddr
der Liste (um den Elementnamen und die Attribute zu überspringen). Sobald Sie das tun, sollten Sie feststellen, dass alle Listen korrekt sind und Ihr Problem verschwindet. Es behebt auch einen Fehler in Ihrem Code, durch den Sie eintd
Attribut für eintd
Element verwechseln können .Antworten:
Es erfüllt
listp
, also in diesem Sinne ist es eine Liste.listp
testet nur, ob etwas ein Nachteil ist odernil
(aka()
) einerseits oder etwas anderes andererseits.Eine richtige Liste oder eine echte Liste (oder eine Liste, die keine gepunktete Liste oder eine zirkuläre Liste ist) ist etwas, das
listp
auchnil
als letzte CDR vorhanden ist. Das heißt, eine ListeXS
ist die richtige , wenn(cdr (last XS))
istnil
(und das ist , wie man es unterscheiden).Ein anderer Weg, dies zu formulieren, ist, dass eine richtige Liste eine richtige Liste als ihre cdr hat . Dies ist die Art und Weise der Datentyp (richtige) Liste wird in typisierten Sprachen definiert. Es handelt sich um eine generische und rekursive Typdefinition: Der generische Teil besagt, dass das erste Argument für den nicht leeren Listenkonstruktor (oft
cons
BTW genannt) von einem beliebigen Typ sein kann. Der rekursive Teil besagt, dass sein zweites Argument eine Instanz des Typs (richtige) Liste ist .Ja, Sie überprüfen mit
listp
is , ob eine gegebene Liste richtig(cdr (last XS))
istnil
. Um zu überprüfen, ob die cdr des Lebewesens selbst eine richtige Liste ist, müssen Sie die cdr bis zum Ende überprüfen - die letzten Nachteile, um festzustellen, ob dies der Fall istnil
. Sie könnten ein Prädikat dafür wie folgt definieren, wenn Sie möchten:Obwohl eine Zirkelliste kein Ende hat, ist Emacs (beginnend mit Emacs 24) intelligent genug, um eine
last
korrekte Überprüfung durchzuführen. Daher funktioniert dieser Code auch für eine Zirkelliste (jedoch nur für Emacs 24.1 und höher; für frühere Versionen erhalten Sie eine "unendliche" Rekursion bis zum Stapelüberlauf).Sie können Funktionen beispielsweise
length
nur für ordnungsgemäße Listen und andere Sequenzen verwenden. Siehe auch Funktionsafe-length
.Siehe das Elisp-Handbuch, Knoten Cons Cells .
Was die Notation betrifft ,
(a b)
ist dies nur syntaktischer Zucker für(a . (b . nil))
- siehe das Elisp-Handbuch, Knoten- Notation für gepunktete Paarequelle
(cdr (last XS))
istnil
ist crumblesome. Gibt es nicht eine Funktion wieproper-list-p
?(unless (atom x) (not (cdr (last x))))
Du selbst anrufen(true-list-p "text")
undnil
keinen Fehler bekommen kannst .nil
(dhlistp
). (Auch FWIW, ich nicht verwendenunless
oderwhen
für deren Rückgabewert ich verwende.and
,or
Undif
für das.)