รายการ '(a. b) เป็นจริงหรือไม่


15

ฉันสับสนกับ.สัญกรณ์จริงๆ คือ'(a . b)รายการ?

(listp '(a . b))ผลตอบแทนที่ได้tแต่เมื่อฉันต้องการที่จะทราบความยาวของมันให้ข้อผิดพลาด(length '(a . b)) Wrong type argument: listp, bเช่นเดียวกับฟังก์ชั่นอื่น ๆ เช่นnth,mapcarอื่น ๆ พวกเขาทั้งหมดให้ข้อผิดพลาดเดียวกัน

มีฟังก์ชั่นใดบ้างที่ฉันสามารถแยกความแตกต่างระหว่าง'(a b)และ'(a . b)?


บริบท:ผมพบปัญหานี้เมื่อฉันต้องการที่จะใช้รุ่น recursive mapcarของ นี่คือการดำเนินการของฉัน

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

ฉันใช้สิ่งนี้เพื่อแยกแท็กเฉพาะทั้งหมดออกจากการแยกวิเคราะห์ HTML ตัวอย่างของhtmlการแยกวิเคราะห์

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

จากนั้นฉันก็สกัดทั้งหมด<td>เป็น

(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
ไม่มีtrue-list-pใน Elisp เพียงเพราะไม่พบว่ามีประโยชน์เพียงพอที่จะให้ จริง ๆ แล้วฉันจำไม่ได้ว่าครั้งสุดท้ายที่ฉันต้องการทดสอบว่ารายการนั้นเหมาะสมหรือไม่ดังนั้นถ้าคุณให้ข้อมูลเพิ่มเติมเล็กน้อยเกี่ยวกับกรณีการใช้งานของคุณเราสามารถช่วยคุณแก้ปัญหาของคุณได้ด้วยวิธีอื่น
Stefan

@tefan ในระยะสั้นฉันต้องการใช้แผนที่แบบเรียกซ้ำฉันประเมินฟังก์ชั่นที่กำหนดในองค์ประกอบของรายการที่กำหนดจากนั้นในองค์ประกอบขององค์ประกอบของรายการจากนั้นองค์ประกอบขององค์ประกอบขององค์ประกอบของรายการและอื่น ๆ ดังนั้นฉันต้องรู้ว่าองค์ประกอบนั้นเป็นรายการจริงหรือไม่
ทอม

มันมีประโยชน์เช่นเมื่อฉันแยกวิเคราะห์ HTML ด้วยlibxml-parse-html-regionและฉันต้องการแยก<td>แท็กทั้งหมด
ทอม

คุณช่วยแสดงตัวอย่างที่เป็นรูปธรรมที่คุณอาจได้รับรายการที่เหมาะสมหรือรายการที่ไม่เหมาะสมหรืออย่างอื่นและคุณต้องจัดการกับ 3 กรณีที่แตกต่างกันหรือไม่? ในกรณีส่วนใหญ่ฉันต้องจัดการกับกรณี "เหมาะสม" และ "ไม่เหมาะสม" สามารถแชร์จนกว่าเราจะไปถึงหางที่ไม่เหมาะสมจริงดังนั้นคุณไม่จำเป็นต้องทดสอบว่าเหมาะสมหรือไม่: เพียงแค่ทดสอบว่า มันconspแทน
Stefan

1
libxml ไม่เพียงแค่คืนค่ารายการของรายการ แต่ละรายการที่เป็นตัวแทนขององค์ประกอบ XML มีรูปแบบ (คุณสมบัติสัญลักษณ์. เนื้อหา) ดังนั้นรหัสของคุณไม่ควรใช้ mapcar ซ้ำกับองค์ประกอบทั้งหมดของรายการเพียงผ่านcddrรายการ (เพื่อข้ามชื่อองค์ประกอบและแอตทริบิวต์) เมื่อคุณทำเช่นนั้นคุณควรพบว่ารายการทั้งหมดมีความเหมาะสมและปัญหาของคุณจะหายไป นอกจากนี้ยังจะแก้ไขข้อบกพร่องในรหัสของคุณซึ่งคุณอาจสร้างความสับสนtdให้กับtdองค์ประกอบสำหรับองค์ประกอบ
Stefan

คำตอบ:


22

มันน่าพอใจlistpดังนั้นในแง่นี้มันจึงเป็นรายการ listpเพียงแค่ทดสอบว่ามีอะไรเป็นข้อเสียหรือnil(aka ()) ในอีกด้านหนึ่งหรืออย่างอื่นในอีกทางหนึ่ง

รายการที่เหมาะสมหรือรายการที่แท้จริง (หรือรายการที่ไม่ได้เป็นรายการจุดหรือรายการกลม) เป็นสิ่งที่เป็นlistpและยังมีnilเป็น CDR สุดท้าย นั่นคือรายการXSจะถูกต้องถ้า(cdr (last XS))เป็นnil(และนั่นคือวิธีที่คุณแยกแยะมัน)

วิธีที่จะนำนี้ก็คือว่าเป็นรายการที่เหมาะสมมีรายชื่อที่เหมาะสมเป็น CDR นี่คือวิธีที่ชนิดข้อมูล (เหมาะสม) รายการที่กำหนดไว้ในพิมพ์ภาษา มันเป็นคำจำกัดความชนิดทั่วไปและแบบเรียกซ้ำ: ส่วนทั่วไปบอกว่าอาร์กิวเมนต์แรกของตัวสร้างรายการที่ไม่ว่าง (มักเรียกว่าconsBTW) สามารถเป็นประเภทใดก็ได้ ส่วนที่บอกว่า recursive อาร์กิวเมนต์ที่สองเป็นตัวอย่างของประเภท (ที่เหมาะสม) รายการ

ใช่คุณตรวจสอบว่าได้รับlistpเป็นรายการที่เหมาะสมใช้เป็น(cdr (last XS)) nilในการตรวจสอบว่า cdr ของ critter นั้นเป็นรายการที่เหมาะสมหรือไม่คุณต้องตรวจสอบ cdr ของมันต่อไปจนถึงตอนจบ - ข้อเสียสุดท้ายเพื่อดูว่าเป็นnilหรือไม่ คุณสามารถกำหนดภาคแสดงสำหรับสิ่งต่อไปนี้หากคุณต้องการ:

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

แม้ว่ารายการเวียนไม่มีสิ้นสุด Emacs (เริ่มต้นด้วย Emacs 24) ฉลาดพอที่จะตรวจสอบlastได้อย่างถูกต้องดังนั้นรหัสนี้ใช้ได้แม้กับรายการเวียน (แต่สำหรับ Emacs 24.1 ขึ้นไปเท่านั้น) สำหรับรุ่นก่อนหน้าคุณจะได้รับการเรียกซ้ำแบบไม่มีที่สิ้นสุด จนกระทั่งกองล้น)

คุณสามารถใช้ฟังก์ชั่นเช่นlengthเฉพาะในรายการที่เหมาะสมและลำดับอื่น ๆ safe-lengthดูเพิ่มเติมทำงาน

ดู Elisp คู่มือโหนดจุดด้อยเซลล์

สำหรับสัญกรณ์นั้น(a b)เป็นเพียงน้ำตาล syntactic สำหรับ(a . (b . nil))- ดูคู่มือ Elisp, โหนดจุดคู่สัญกรณ์


แนวปฏิบัติที่ดีที่สุดในการตรวจสอบรายการที่เหมาะสมคืออะไร ตรวจสอบว่า(cdr (last XS))เป็นnilเป็น crumblesome มีฟังก์ชั่นproper-list-pใช่ไหม?
ทอม

@ ทอม: นั่นหรือสิ่งที่เทียบเท่าคุณจำเป็นต้องตรวจสอบเซลล์ข้อเสียสุดท้าย ฉันได้เพิ่มเกี่ยวกับสิ่งนี้ในคำตอบตอนนี้
Drew

@ ดึงฉันจะเปลี่ยนร่างกายของฟังก์ชั่นเพื่อ(unless (atom x) (not (cdr (last x))))ให้คุณสามารถโทร(true-list-p "text")และnilไม่ได้รับข้อผิดพลาด
ทอม

@tom: ถูกต้อง; ขอบคุณ. ที่จริงควรทดสอบก่อนเพื่อให้แน่ใจว่าเป็นข้อเสียหรือnil(เช่นlistp) (นอกจากนี้ FWIW, ฉันไม่ได้ใช้unlessหรือwhenค่าที่ส่งกลับของพวกเขาผมใช้. and, orและifสำหรับที่.)
ดึง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.