จะทราบได้อย่างไรว่าจะใช้อัญประกาศเดี่ยวข้างหน้าชื่อตัวแปรเมื่อใดหรือไม่


31

ฉันมีด้านล่าง:

(setq some-variable "less")

ฉันกำลังสับสนว่าทำไมผมต้องใช้คำพูดเดียวกับแต่ไม่ได้มีboundpbound-and-true-p

ตัวอย่างที่ 1:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))

ผล:

"บางตัวแปรน้อย"

ตัวอย่าง 2a:

(when (bound-and-true-p some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

ผล:

"บางตัวแปรน้อย"

ตัวอย่าง 2b:

(when (bound-and-true-p 'some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

ผล:

และ: อาร์กิวเมนต์ชนิดผิด: symbolp, (อ้างถึงตัวแปรบางตัว)


5
มันเป็นมูลค่าการกล่าวขวัญว่าsetqย่อมาset quotedและ (set 'some-variable "less")แต่เดิมเป็นแมโครที่ขยายตัวใน โดยทั่วไปแล้ว Elisp ไม่สอดคล้องกันอย่างมากกับข้อโต้แย้งที่ยกมาและไม่มีข้อโต้แย้ง แต่ฟังก์ชั่นใด ๆ (ไม่ใช่มาโคร) ที่จำเป็นต้องมีปฏิสัมพันธ์กับตัวแปรแทนค่าจะใช้อาร์กิวเมนต์ที่ยกมา ( setqเป็นข้อยกเว้นที่สำคัญ)
shosti

2
FWIW bound-and-true-pเป็นมาโครโง่ หรือค่อนข้างชื่อของมันคือโง่ 99.99% ของเวลาที่คุณต้องการที่จะทำ(and (boundp 'FOO) FOO)คุณทำมันจะใช้ค่าของ FOOคุณไม่ได้ทำแค่เพื่อให้ได้คุณค่าจริง (1) ไม่จำเป็นต้องใช้แมโคร - รหัสที่ใช้แทนนั้นมีขนาดเล็กและใหญ่ (2) เป็นชื่อที่ทำให้เข้าใจผิด - nilมันเป็นเรื่องเกี่ยวกับค่าตัวแปรไม่ได้เป็นเพียงการทดสอบหรือไม่ว่าค่าตัวแปรคือ
ดึง

คำตอบ:


24

คำตอบสั้น ๆ

'some-variableถ้าคุณกำลังพยายามที่จะใช้ตัวแปรของตัวเองแล้วใช้ some-variableถ้าคุณกำลังพยายามที่จะใช้ค่าที่เก็บไว้ในตัวแปรที่ใช้

  • boundp ใช้สัญลักษณ์เพื่อดูสิ่งที่สามารถผูกรวมถึงฟังก์ชั่น มันแค่ใส่ใจว่ามีสัญลักษณ์ที่ตรงกันหรือไม่ไม่ใช่ค่าที่เป็น
  • bound-and-truep ใช้ var และส่งคืนค่า ในกรณีนี้คุณต้องระบุค่าของสัญลักษณ์ให้กับฟังก์ชัน ถ้าไม่มีสัญลักษณ์ var ถูกผูกไว้หรือค่าเป็นศูนย์มันจะส่งคืนศูนย์

คำอธิบาย

สำหรับคำนิยามคู่มือโปรดดูคู่มือการใช้งาน

'และ(quote ...)ทั้งสองทำหน้าที่เดียวกันใน emacs-lisp

จุดประสงค์ของการทำแบบนี้คือการส่งแบบฟอร์มที่ไม่ได้ประเมินไปยังสภาพแวดล้อมโดยรอบแทนที่จะประเมิน

ในตัวอย่างของคุณสมมติว่าเรามีดังต่อไปนี้สูงขึ้น

(setq some-variable "less") ;; Rather than just 't for clarity

จากนั้นการประเมินจะเป็นดังนี้:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))
;; ==> (boundp 'some-variable) ; 't
;; ==> some-variable is "less"

ในขณะที่ไม่มีใบเสนอราคา:

(when (boundp some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))
;; ==> (boundp "less") ; "less" is not a variable. -> Error

เสียงกระเพื่อมประเมินรูปแบบที่พวกเขาจะมาถึงโดยการอ้างถึงรูปแบบที่คุณป้องกันการประเมินเพื่อให้ตัวแปรที่แท้จริง (หรือรายการหรือชื่อฟังก์ชั่น) จะถูกส่งผ่าน


ขอบคุณ! คำตอบของคุณทำให้ฉันกระโดดเข้าสู่แหล่งที่มาของทั้งสองและช่วยฉันแก้ปัญหา ฉันได้อัปเดตคำถามของฉันด้วยตัวอย่างที่ชัดเจน
Kaushal Modi

6
ฉันดีใจที่สิ่งนี้ช่วย op แต่มันไม่ได้ตอบคำถาม (ในทางที่เป็นประโยชน์สำหรับคนอื่นที่มีคำถามเดียวกัน) คุณอธิบายได้เพียงว่าต้องมีการอ้างถึงสัญลักษณ์หรือมีการประเมินสัญลักษณ์ คุณไม่ได้อธิบายว่าทำไมที่ไม่ได้เป็นกรณีที่bound-and-truepและคำถามที่ถูกทำไมฉันต้องอ้างเมื่อใช้แต่ไม่เมื่อใช้boundp bound-and-truep
Tarsius

@tarsius จริงผมรวมถึงความแตกต่างกันระหว่างboundpกำหนดให้เป็นสัญลักษณ์ (unevaluated) และbound-and-truepต้องค่าของตัวแปรในจุดที่กระสุน (แก้ไขหลังจากคำตอบที่เริ่มต้น)
โจนาธานปลิง-Pepin

ฉันคิดว่ามันเป็นสิ่งสำคัญที่จะกล่าวถึงสาเหตุที่เป็นเช่นนั้น (มาโครอาจเลือกที่จะไม่ประเมิน) แทนที่จะพูดถึงว่า doc-string พูดอย่างนั้น ฉันคิดว่านี่เป็นคำถามที่ดีมากและ boundp กับ bound-and-true-p เป็นเพียงตัวอย่างเท่านั้น คำถามที่เดือดร้อนจริงๆคือความปรารถนาที่จะเรียนรู้เกี่ยวกับกฎการประเมิน
Tarsius

@tarsius ไม่ได้อธิบายกฎการประเมินผลโดยคำตอบนี้หรือไม่ อย่างน้อยคนพื้นฐานที่เกี่ยวข้องกับคำพูดเท่านั้น ... คำตอบของคุณนั้นสมบูรณ์มากขึ้น แต่มันไปไกลกว่าหัวข้อใช่ไหม?
T. Verron

16

สัญลักษณ์ที่อยู่ในตำแหน่งที่ไม่ใช่ฟังก์ชั่นถือเป็นชื่อของตัวแปร In (function variable) functionอยู่ในตำแหน่งฟังก์ชั่น (หลังจากวงเล็บเปิด) และvariableไม่ใช่ ตัวแปรที่ยกมาอย่างชัดเจนนอกจากจะถูกแทนที่ด้วยค่าของพวกเขา

หากคุณกำลังจะเขียน(boundp my-variable)นั่นจะหมายถึง "เป็นสัญลักษณ์ที่ถูกเก็บไว้ในค่าของตัวแปรที่my-variableถูกผูกไว้เป็นตัวแปร" และไม่ได้ "เป็นสัญลักษณ์ที่my-variableถูกผูกไว้เป็นตัวแปร

เหตุใดจึงมีbound-and-truepพฤติกรรมแตกต่างกัน

นี่เป็นมาโครและกฎการประเมิน (ฟังก์ชั่น) ปกติไม่ได้ใช้ที่นี่มาโครมีอิสระในการตัดสินใจว่าจะประเมินอาร์กิวเมนต์เมื่อใดและเมื่อใด มาโครที่ทำจริง ๆ จะเปลี่ยนอาร์กิวเมนต์และส่งคืนผลลัพธ์เป็นรายการซึ่งจะถูกประเมินผล การเปลี่ยนแปลงและการประเมินผลขั้นสุดท้ายเกิดขึ้นในเวลาที่ต่างกันเรียกว่าการขยายตัวของเวลามหภาคและการประเมินผลเวลา

นี่คือbound-and-true-pลักษณะของคำจำกัดความของลักษณะ:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

ใช้มาโครของเครื่องอ่านซึ่งแตกต่างจากมาโคร lisp (เพิ่มเติมจากด้านล่าง) หากต้องการไม่ทำให้ซับซ้อนมากขึ้นอีกโปรดอย่าใช้มาโครของเครื่องอ่าน:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  (list 'and (list 'boundp (list 'quote var)) var))

ถ้าคุณเขียน

(bound-and-true-p my-variable)

นั่นคือ "แปล" เป็นครั้งแรก

(and (boundp 'my-variable) my-variable)

และนั่นคือการประเมินผลตอบแทนnilถ้าmy-variableไม่ใช่boundpหรือมิฉะนั้นมูลค่าของmy-variable(ซึ่งแน่นอนว่าสามารถเป็นได้nil)


คุณอาจสังเกตเห็นว่าการขยายตัวไม่ใช่

(and (boundp (quote my-variable)) my-variable)

อย่างที่เราคาดหวัง quoteเป็นรูปแบบพิเศษไม่ใช่แมโครหรือฟังก์ชัน เช่นเดียวกับมาโครรูปแบบพิเศษสามารถทำอะไรก็ได้กับข้อโต้แย้งของพวกเขา รูปแบบพิเศษนี้จะคืนค่าอาร์กิวเมนต์ของมันที่นี่เป็นสัญลักษณ์แทนค่าตัวแปรของสัญลักษณ์ นั่นคือจุดประสงค์เดียวของรูปแบบพิเศษนี้: การป้องกันการประเมิน! มาโครไม่สามารถทำได้ด้วยตนเองพวกเขาจำเป็นต้องใช้quoteเพื่อทำเช่นนั้น

ดังนั้นสิ่งที่เกิดขึ้นด้วย'? มันเป็นแมโครผู้อ่านซึ่งเป็นที่กล่าวถึงข้างต้นไม่ได้เช่นเดียวกับแมโครกระเพื่อม แม้ว่าแมโครจะใช้ในการแปลงรหัส / ข้อมูล แต่แมโครของเครื่องอ่านจะใช้ก่อนหน้านี้เมื่ออ่านข้อความเพื่อแปลงข้อความนั้นเป็นรหัส / ข้อมูล

'something

เป็นรูปแบบย่อสำหรับ

(quote something)

`ใช้ในความหมายที่แท้จริงของbound-and-true-pยังเป็นมาโครอ่าน หากเครื่องหมายคำพูดเป็นสัญลักษณ์ใน`symbolนั้นเทียบเท่ากับ'symbolแต่เมื่อใช้ในการอ้างอิงรายการตามที่`(foo bar ,baz)มันทำงานแตกต่างกันในรูปแบบที่จะนำหน้าด้วย,จะถูกประเมิน

`(constant ,variable)

เทียบเท่ากับ

(list (quote constant) variable))

สิ่งนี้ควรตอบคำถามที่ว่าทำไมบางครั้งสัญลักษณ์ที่ไม่ได้อ้างอิงถูกประเมิน (แทนที่ด้วยค่า) และบางครั้งก็ไม่ แมโครสามารถใช้quoteเพื่อป้องกันไม่ให้มีการประเมินสัญลักษณ์

แต่ทำไมbound-and-true-pมาโครถึงboundpไม่ได้? เราจะต้องสามารถตรวจสอบว่าสัญลักษณ์ใด ๆ ที่ไม่รู้จักจนถึงเวลาทำงานนั้นถูกผูกไว้เป็นสัญลักษณ์หรือไม่ สิ่งนี้จะเป็นไปไม่ได้หากboundpมีการเสนอราคาโดยอัตโนมัติ

bound-and-true-pใช้เพื่อตรวจสอบว่ามีการกำหนดตัวแปรที่รู้จักและใช้ค่าของมัน สิ่งนี้มีประโยชน์หากไลบรารีมีการอ้างอิงเพิ่มเติมในไลบรารีบุคคลที่สามเช่นเดียวกับใน:

(defun foo-get-value ()
  (or (bound-and-true-p bar-value)
      ;; we have to calculate the value ourselves
      (our own inefficient or otherwise undesirable variant)))

bound-and-true-pอาจจะหมายถึงฟังก์ชั่นและต้องมีการโต้แย้งที่จะยกมา 'แต่เพราะมันมีไว้สำหรับกรณีที่คุณรู้ล่วงหน้าสิ่งที่ตัวแปรคุณดูแลเกี่ยวกับแมโครถูกใช้ในการช่วยให้คุณประหยัดจากที่มีการพิมพ์


ตอบอย่างน่าอัศจรรย์
Charles Ritchie

2

จากซอร์สโค้ดของboundp:

DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
      doc: /* Return t if SYMBOL's value is not void.
Note that if `lexical-binding' is in effect, this refers to the
global value outside of any lexical scope.  */)

boundpคาดว่าจะsymbolเป็นอินพุต เป็นสัญลักษณ์ให้กับตัวแปร'some-variablesome-variable

จากซอร์สโค้ดของbound-and-true-p:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

bound-and-true-pคาดว่าจะvariableเป็นอินพุต

ภายในแมโครจะได้รับสัญลักษณ์โดยการทำbound-and-true-p (quote ,var)ดังนั้นถ้าใส่เป็นsome-variable, จะส่งผลให้(quote ,var)'some-variable

แต่เมื่อฉันให้การป้อนข้อมูล'some-variableเพื่อbound-and-true-pฉันได้รับข้อผิดพลาด: and: Wrong type argument: symbolp, (quote some-variable)เนื่องจากแมโครไม่ได้คาดหวังว่าสัญลักษณ์ ( 'some-variable) ในการป้อนข้อมูล


เพียงแค่หัวขึ้น ''symbol ไม่เข้าท่า (quote (quote symbol))มันหมายความว่า boundpเหตุผลที่คุณจะได้รับข้อผิดพลาดก็คือว่ามันไม่ได้เป็นข้อโต้แย้งที่ถูกต้อง
Malabarba

@ Malabarba ขอบคุณ ฉันได้ทำการแก้ไข
Kaushal Modi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.