Saya benar-benar bingung dengan .
notasi. Apakah '(a . b)
daftar?
(listp '(a . b))
kembali t
tetapi ketika saya ingin tahu panjangnya (length '(a . b))
memberikan kesalahan Wrong type argument: listp, b
. Hal yang sama untuk fungsi lain seperti nth,mapcar
dll. Mereka semua memberikan kesalahan yang sama
Apakah ada fungsi yang bisa saya bedakan antara '(a b)
dan '(a . b)
?
Konteks: Saya mengalami masalah ini ketika saya ingin mengimplementasikan versi rekursif dari mapcar
. Ini implementasi saya
(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))
Saya menggunakan ini untuk mengekstrak semua tag tertentu dari html parsed. Contoh html
untuk menguraikan
;; 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>
Lalu saya mengekstrak semua <td>
sebagai
(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
di Elisp hanya karena belum ditemukan cukup berguna untuk menyediakannya. Memang, saya tidak ingat kapan terakhir kali saya ingin menguji apakah daftar itu benar, jadi mungkin jika Anda memberi kami sedikit lebih banyak informasi tentang kasus penggunaan Anda, kami dapat membantu Anda memecahkan masalah Anda dengan cara lain.libxml-parse-html-region
dan saya ingin mengekstrak semua<td>
tag.consp
malah.cddr
daftar (untuk melewati nama elemen dan atribut). Setelah Anda melakukannya, Anda harus menemukan bahwa semua daftar sudah benar dan masalah Anda akan hilang. Ini juga akan memperbaiki bug dalam kode Anda di mana Anda dapat mengacaukantd
atribut untuktd
elemen.Jawaban:
Itu memuaskan
listp
, jadi dalam arti itu adalah daftar.listp
hanya menguji apakah ada yang kontra ataunil
(alias()
), di satu sisi, atau sesuatu yang lain, di sisi lain.Sebuah daftar yang tepat atau daftar yang benar (atau daftar yang tidak daftar titik-titik atau daftar melingkar) adalah sesuatu yang
listp
dan juga memilikinil
sebagai cdr terakhir. Artinya, daftarXS
adalah tepat jika(cdr (last XS))
adalahnil
(dan itu adalah bagaimana Anda membedakannya).Cara lain untuk menempatkan ini adalah bahwa daftar yang tepat memiliki daftar yang tepat sebagai cdr-nya . Ini adalah cara tipe data (benar) Daftar didefinisikan dalam bahasa yang diketik. Ini adalah definisi tipe generik dan rekursif: Bagian generik mengatakan bahwa argumen pertama ke konstruktor daftar tidak kosong (sering disebut
cons
, BTW) dapat dari jenis apa pun. Bagian rekursif mengatakan bahwa argumen kedua adalah turunan dari tipe (benar) Daftar .Ya, Anda memeriksa apakah daftar yang diberikan
listp
benar atau(cdr (last XS))
tidaknil
. Untuk memeriksa apakah cdr makhluk itu sendiri adalah daftar yang tepat, Anda harus terus memeriksa cdrnya, hingga akhir - kontra terakhir, untuk melihat apakah itunil
. Anda dapat menetapkan predikat untuk ini sebagai berikut, jika Anda ingin:Meskipun daftar bundar tidak memiliki akhir, Emacs (dimulai dengan Emacs 24) cukup pintar untuk memeriksa
last
dengan benar, sehingga kode ini berfungsi bahkan untuk daftar melingkar (tetapi hanya untuk Emacs 24.1 dan yang lebih baru; untuk versi sebelumnya Anda mendapatkan rekursi "tak terbatas" sampai stack overflow).Anda dapat menggunakan fungsi seperti
length
hanya pada daftar yang benar dan urutan lainnya. Lihat juga fungsisafe-length
.Lihat manual Elisp, Sel Cons node .
Adapun notasi,
(a b)
hanya gula sintaksis untuk(a . (b . nil))
- lihat manual Elisp, Notasi Dotted Pairsumber
(cdr (last XS))
ininil
adalah crumblesome. Apakah tidak ada fungsi seperti ituproper-list-p
?(unless (atom x) (not (cdr (last x))))
Jadi Anda bahkan dapat menelepon(true-list-p "text")
dannil
tidak mendapatkan kesalahan.nil
(yaitu,listp
). (Juga, FWIW, saya tidak menggunakanunless
atauwhen
untuk nilai mereka kembali saya gunakan.and
,or
Danif
untuk itu.)