Jestem naprawdę pomylony z .
notacją. Jest '(a . b)
lista?
(listp '(a . b))
zwraca, t
ale gdy chcę wiedzieć, jego długość (length '(a . b))
powoduje błąd Wrong type argument: listp, b
. To samo dotyczy innych funkcji nth,mapcar
itp., Wszystkie dają ten sam błąd
Czy jest jakaś funkcja, która mogę rozróżnić '(a b)
i '(a . b)
?
Kontekst: napotkałem ten problem, gdy chciałem zaimplementować wersję rekurencyjną mapcar
. Oto moja implementacja
(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))
Używam tego do wyodrębnienia wszystkich określonych tagów z przeanalizowanego HTML. Przykład html
analizy
;; 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>
Następnie wyodrębniam wszystko <td>
jako
(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
)
)
list
association-lists
Tomek
źródło
źródło
true-list-p
w Elisp po prostu dlatego, że nie został uznany za przydatny wystarczy do jej świadczenia. Rzeczywiście, nie pamiętam, kiedy ostatni raz chciałem sprawdzić, czy lista jest odpowiednia, więc może jeśli podasz nam nieco więcej informacji na temat swojego przypadku użycia, możemy pomóc Ci rozwiązać problem w inny sposób.libxml-parse-html-region
i chcę wyodrębnić wszystkie<td>
tagi.consp
zamiast tego.cddr
listą (aby pominąć nazwę elementu i atrybuty). Gdy to zrobisz, powinieneś stwierdzić, że wszystkie listy są prawidłowe, a Twój problem zniknie. Naprawi to również błąd w kodzie, w którym możesz pomylićtd
atrybuttd
elementu.Odpowiedzi:
Spełnia
listp
, więc w tym sensie jest to lista.listp
po prostu sprawdza, czy coś jest wadą lubnil
(aka()
) z jednej strony, czy coś innego z drugiej strony.Właściwa lista lub prawdziwe listy (lub lista nie jest przerywana lista lub lista okrągły) jest czymś
listp
, a także posiadanil
w swoim ostatnim CDR. Oznacza to, że listaXS
jest poprawna, jeśli(cdr (last XS))
jestnil
(i tak ją rozróżniasz).Innym sposobem na wyrażenie tego jest to, że właściwa lista ma właściwą listę jako cdr . W ten sposób lista typów danych (właściwa) jest definiowana w językach pisanych na maszynie. Jest to ogólna i rekurencyjna definicja typu: Część ogólna mówi, że pierwszy argument niepustego konstruktora listy (często nazywanego
cons
BTW) może być dowolnego typu. Część rekurencyjna mówi, że jej drugim argumentem jest instancja typu (właściwa) Lista .Tak, sprawdzasz, czy dana
listp
lista(cdr (last XS))
jest poprawna, używającnil
. Aby sprawdzić, czy cdr samego crittera jest właściwą listą, musisz kontynuować sprawdzanie jego cdr, aż do końca - ostatnich wad, aby zobaczyć, czy tak jestnil
. Możesz zdefiniować predykat dla tego w następujący sposób, jeśli chcesz:Chociaż okrągła lista nie ma końca, Emacs (począwszy od Emacsa 24) jest wystarczająco inteligentny, aby sprawdzić
last
poprawnie, więc ten kod działa nawet w przypadku okrągłej listy (ale tylko w Emacsie 24.1 i nowszych; we wcześniejszych wersjach otrzymujesz „nieskończoną” rekurencję aż do przepełnienia stosu).Możesz używać funkcji takich jak
length
tylko na odpowiednich listach i innych sekwencjach. Zobacz także funkcjęsafe-length
.Zobacz instrukcję Elisp, węzeł Cons Cells .
Jeśli chodzi o notację,
(a b)
to tylko cukier syntaktyczny(a . (b . nil))
- patrz instrukcja Elisp, notacja pary kropkowanejźródło
(cdr (last XS))
jestnil
to crumblesome. Czy nie ma takiej funkcjiproper-list-p
?(unless (atom x) (not (cdr (last x))))
Tak, abyś mógł nawet zadzwonić(true-list-p "text")
inil
nie dostać błędu.nil
(tjlistp
.). (Również FWIW, nie używaćunless
lubwhen
ich wartości zwracanej używam.and
,or
Iif
za to.)