Là '(a. B) thực sự là một danh sách?


15

Tôi thực sự bối rối với .ký hiệu. Là '(a . b)một danh sách?

(listp '(a . b))trả về tnhưng khi tôi muốn biết chiều dài của nó (length '(a . b))báo lỗi Wrong type argument: listp, b. Điều tương tự là đối với các chức năng khác, nth,mapcarv.v ... tất cả đều có cùng một lỗi

Có chức năng nào tôi có thể phân biệt giữa '(a b)'(a . b)?


Bối cảnh: Tôi gặp phải vấn đề này khi tôi muốn triển khai phiên bản đệ quy của mapcar. Đây là cách thực hiện của tôi

(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))

Tôi sử dụng điều này để trích xuất tất cả các thẻ cụ thể từ html được phân tích cú pháp. Ví dụ về htmlphân tích cú pháp

;; 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>

Sau đó tôi trích xuất tất cả <td>như

(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
    )
  )

1
Không có true-list-ptrong Elisp đơn giản vì nó chưa được tìm thấy đủ hữu ích để cung cấp nó. Thật vậy, tôi không thể nhớ lần cuối cùng tôi muốn kiểm tra xem một danh sách có phù hợp hay không, vì vậy có lẽ nếu bạn cung cấp cho chúng tôi thêm một chút thông tin về trường hợp sử dụng của bạn, chúng tôi có thể giúp bạn giải quyết vấn đề của bạn theo cách khác.
Stefan

@Stefan Tóm lại, tôi muốn triển khai mapcar đệ quy, tôi đánh giá hàm đã cho trên các phần tử của danh sách đã cho, sau đó vào các phần tử của các phần tử của danh sách, sau đó về các phần tử của các phần tử của phần tử trong danh sách, v.v. Vì vậy, tôi cần phải biết nếu một yếu tố là một danh sách thực sự hay không.
tom

Nó là hữu ích ví dụ khi tôi phân tích cú pháp html libxml-parse-html-regionvà tôi muốn trích xuất tất cả <td>các thẻ.
tom

Bạn có thể chỉ cho chúng tôi một ví dụ cụ thể trong đó bạn có thể nhận được một danh sách phù hợp, hoặc một danh sách không phù hợp, hoặc một cái gì đó khác, và nơi bạn cần xử lý 3 trường hợp khác nhau? Trong hầu hết các trường hợp tôi đã phải giải quyết, các trường hợp "đúng" và "không đúng" có thể được chia sẻ cho đến khi chúng tôi nhận được đuôi không đúng, vì vậy bạn một lần nữa không cần kiểm tra xem có đúng hay không: chỉ kiểm tra xem nó conspthay thế.
Stefan

1
libxml không chỉ trả về danh sách danh sách. Mỗi danh sách đại diện cho một phần tử XML có dạng (thuộc tính ký hiệu. Nội dung). Vì vậy, mã của bạn không nên áp dụng đệ quy mapcar trên tất cả các thành phần của danh sách, chỉ trên cddrdanh sách (để bỏ qua tên thành phần và thuộc tính). Khi bạn làm điều đó, bạn sẽ thấy rằng tất cả các danh sách là phù hợp và vấn đề của bạn sẽ biến mất. Nó cũng sẽ sửa một lỗi trong mã của bạn, nơi bạn có thể nhầm lẫn một tdthuộc tính cho một tdphần tử.
Stefan

Câu trả lời:


22

Nó thỏa mãn listp, vì vậy theo nghĩa đó, nó là một danh sách. listpchỉ kiểm tra xem một cái gì đó là một khuyết điểm hay nil(aka ()), mặt khác, hay cái gì khác, mặt khác.

Một danh sách phù hợp hoặc danh sách thực sự (hoặc một danh sách không phải là danh sách chấm hoặc danh sách tròn) là một cái gì đó listpvà cũng có nilnhư là cdr cuối cùng của nó. Đó là, một danh sách XSphù hợp nếu (cdr (last XS))nil(và đó là cách bạn phân biệt nó).

Một cách khác để đặt điều này là một danh sách phù hợp có một danh sách phù hợp là cdr của nó . Đây là cách Danh sách kiểu dữ liệu (thích hợp) được xác định bằng các ngôn ngữ được nhập. Đây là một định nghĩa kiểu chung và đệ quy: Phần chung nói rằng đối số đầu tiên cho hàm tạo danh sách không trống (thường được gọi là consBTW) có thể thuộc bất kỳ loại nào. Phần đệ quy nói rằng đối số thứ hai của nó là một thể hiện của Danh sách loại (thích hợp) .

Vâng, bạn kiểm tra xem một định listplà danh sách thích hợp sử dụng (cdr (last XS))nil. Để kiểm tra xem cdr của máy nghiền có phải là một danh sách phù hợp hay không, bạn phải tiếp tục kiểm tra cdr của nó, cho đến cuối - khuyết điểm cuối cùng, để xem liệu nó có nil. Bạn có thể định nghĩa một vị ngữ cho điều này như sau, nếu bạn muốn:

(defun true-listp (object)
  "Return non-`nil' if OBJECT is a true list."
  (and (listp object)  (null (cdr (last object)))))

Mặc dù danh sách vòng tròn không có kết thúc, Emacs (bắt đầu với Emacs 24) đủ thông minh để kiểm tra lastchính xác, do đó, mã này hoạt động ngay cả đối với danh sách vòng tròn (nhưng chỉ với Emacs 24.1 trở lên; đối với các phiên bản trước đó, bạn có được đệ quy "vô hạn" cho đến khi chồng tràn).

Bạn có thể sử dụng các chức năng như lengthchỉ trên danh sách phù hợp và các trình tự khác. Xem thêm chức năng safe-length.

Xem hướng dẫn Elisp, nút Cons Cells .

Đối với ký hiệu, (a b)chỉ là đường cú pháp cho (a . (b . nil))- xem hướng dẫn Elisp, ký hiệu chấm chấm nút


Thực hành tốt nhất để kiểm tra danh sách thích hợp là gì? Kiểm tra nếu (cdr (last XS))nillà crumblesome. Không có chức năng như thế proper-list-pnào?
tom

@tom: Điều đó, hoặc một cái gì đó tương đương, là cần thiết - bạn phải kiểm tra ô khuyết điểm cuối cùng. Tôi đã thêm nhiều hơn về điều này trong câu trả lời ngay bây giờ.
vẽ

@Drew Tôi sẽ thay đổi phần thân của hàm thành (unless (atom x) (not (cdr (last x))))Vì vậy, bạn thậm chí có thể gọi (true-list-p "text")nilkhông gặp lỗi.
tom

@tom: Phải; cám ơn. Trên thực tế, nó nên được kiểm tra trước để đảm bảo đó là một khuyết điểm hoặc nil(tức là listp). (Ngoài ra, FWIW, tôi không sử dụng unlesshoặc whencho giá trị trả về của họ tôi sử dụng. and, orifcho điều đó.)
Drew
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.