ควรใช้คำพูดที่คมชัดเมื่อใด


10

ฉันเห็นคำพูดที่คมชัดถูกใช้ในรหัส eLisp ของผู้อื่นและฉันใช้มันด้วยตัวเอง แต่ฉันไม่ชัดเจนว่าเมื่อใดที่เหมาะสมและเมื่อไม่เหมาะสม

ทุกคนสามารถอธิบายได้อย่างชัดเจนว่าเมื่อใดควรใช้เครื่องหมายคำพูดแหลมคมและควรใช้คำพูดเดี่ยวทั่วไปแทนหรือไม่


3
มีคำถามซ้ำซ้อนมากมายสำหรับคำถามนี้ที่นี่หรือบน SO
phils

เป็นไปได้ที่ซ้ำกันของการแสดงออกแลมบ์ดาเมื่อใด
Andrew Swann

1
ฉันไม่คิดว่ามันจะซ้ำกัน: emacs.stackexchange.com/questions/3595เกี่ยวกับการใช้#'กับแลมบ์ดา (โดยที่คำตอบคือ "ไม่" โดยทั่วไป) ในขณะที่คำถามของ @ izkon ใช้กับการใช้#'สัญลักษณ์แทน
สเตฟาน

คำตอบ:


12

#'เป็นเพียงการจดชวเลขfunctionเช่นเดียวกับที่เป็นชวเลข'quote

คุณสามารถใช้มันได้ทุกที่ที่คุณต้องการระบุถึง byte-compiler หรือ interpreter หรือมนุษย์อ่านว่าอาร์กิวเมนต์ของมันคาดว่าจะเป็น (ถือว่าเป็น) ฟังก์ชั่น

ในบริบทจำนวนมากบริบทจะกำหนดวิธีที่จะจัดการกับอาร์กิวเมนต์หากเช่นคุณเพียงอ้างถึง (ใช้quoteหรือ') แทนการใช้#'(หรือfunction) ตัวอย่างเช่นในบริบทที่มีการใช้สัญลักษณ์สำหรับsymbol-functionคุณสมบัติเท่านั้นเช่นใช้เป็นฟังก์ชันคุณสามารถส่งสัญลักษณ์ (เช่นโดยการอ้างอิงหรือผ่านตัวแปรที่มีค่าเป็นสัญลักษณ์)

แต่บางครั้งรหัสก็ชัดเจนขึ้นถ้าคุณใช้#'ในบริบทดังกล่าว แม้ว่า Emacs-Lisp เองก็เข้าใจว่าสัญลักษณ์นั้นถูกใช้เป็นฟังก์ชันในบริบทดังกล่าว แต่อาจช่วยเน้นเรื่องนี้สำหรับผู้อ่านรหัส

ใน Lisps อื่น ๆ การรักษารูปแบบแลมบ์ดาที่ยกมาอย่างง่าย ๆ (ด้วย') หรือไม่ระบุอาจแตกต่างจากการใช้งานในตำแหน่งหน้าที่เมื่อยกมาใช้function( #') แต่ไม่ใช่ใน Emacs Lisp ใน Emacs Lisp คุณไม่จำเป็นต้องอ้างอิง (ใช้อย่างใดอย่างหนึ่ง'หรือ#') แลมบ์ดาแบบฟอร์มที่คุณต้องการให้ถือว่าเป็นฟังก์ชัน (และไม่ใช่เพียงแค่เป็นรายการ) หากคุณต้องการให้มันจัดการเป็นเพียงรายการกับรถยนต์lambdaฯลฯ แล้วอ้างมัน (พร้อม') - ตัวอย่างด้านล่างแสดงสิ่งนี้

ฟังก์ชั่นไม่ระบุชื่อจาก (elisp) :

- แบบฟอร์มพิเศษ: function function-object

แบบฟอร์มพิเศษนี้ส่งคืนFUNCTION-OBJECTโดยไม่ประเมินค่า

ในสิ่งนี้มันคล้ายกับquote(* note Quoting: :) แต่แตกต่างจาก quoteมันยังทำหน้าที่เป็นบันทึกถึงผู้ประเมิน Emacs และคอมไพเลอร์ไบต์ที่FUNCTION-OBJECTมีวัตถุประสงค์เพื่อใช้เป็นฟังก์ชั่น สมมติว่าFUNCTION-OBJECTเป็นการแสดงออกแลมบ์ดาที่ถูกต้องนี้มีสองผล:

•เมื่อโค้ดถูกคอมไพล์ด้วยไบต์FUNCTION-OBJECTจะถูกคอมไพล์เป็นวัตถุฟังก์ชันไบต์โค้ด (* note การรวบรวมไบต์: :)

•เมื่อเปิดใช้งานการรวมคำศัพท์จะFUNCTION-OBJECTถูกแปลงเป็นการปิด * หมายเหตุการปิด ::

ไวยากรณ์การอ่านเป็นระยะสั้นมือสำหรับการใช้#' functionแบบฟอร์มต่อไปนี้เทียบเท่าทั้งหมด:

(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))

ในตัวอย่างต่อไปนี้เรากำหนดchange-propertyฟังก์ชั่นที่ใช้ฟังก์ชั่นเป็นอาร์กิวเมนต์ที่สามของมันตามด้วยdouble-property ฟังก์ชั่นที่ทำให้การใช้งานchange-propertyโดยผ่านมันเป็นฟังก์ชั่นที่ไม่ระบุชื่อ:

(defun change-property (symbol prop function)
   (let ((value (get symbol prop)))
     (put symbol prop (funcall function value))))

(defun double-property (symbol prop)
   (change-property symbol prop (lambda (x) (* 2 x))))

โปรดทราบว่าเราไม่ได้อ้างlambdaแบบฟอร์ม

หากคุณรวบรวมรหัสข้างต้นฟังก์ชั่นที่ไม่ระบุชื่อก็จะรวบรวม สิ่งนี้จะไม่เกิดขึ้นถ้าคุณได้สร้างฟังก์ชั่นนิรนามโดยอ้างว่าเป็นรายการ:

(defun double-property (symbol prop)
   (change-property symbol prop '(lambda (x) (* 2 x))))

ในกรณีนั้นฟังก์ชั่นที่ไม่ระบุชื่อจะถูกเก็บไว้เป็นนิพจน์แลมบ์ดาในรหัสที่รวบรวม คอมไพเลอร์ไบต์ไม่สามารถสันนิษฐานว่ารายการนี้เป็นฟังก์ชั่นแม้ว่ามันจะดูเหมือนเป็นหนึ่งเพราะมันไม่ทราบว่า change-propertyตั้งใจที่จะใช้มันเป็นฟังก์ชั่น


9

#'(aka function) สามารถนำมาใช้ในด้านหน้าของแต่มันซ้ำซ้อนมีเพื่อให้เป็นสถานที่เดียวที่มันมีความหมายจริงๆคือในด้านหน้าของสัญลักษณ์ในขณะที่(lambda ...) #'carใน ELisp #'carและ'carเกือบเทียบเท่าอย่างสมบูรณ์ดังนั้นหนึ่งในวัตถุประสงค์หลักคือเพื่อบันทึกความตั้งใจ (เช่นเพื่อระบุว่าใครก็ตามที่อ่านรหัสนี้ว่าคุณตั้งใจจะใช้สัญลักษณ์นี้เป็นฟังก์ชัน) แต่มีบางสถานการณ์ที่ความแตกต่างสำคัญกว่า:

  • คอมไพเลอร์ไบต์ใช้ประโยชน์จากความตั้งใจที่เป็นเอกสารนี้และเมื่อคุณเขียน#'carมันจะตรวจสอบว่าcarมีอยู่เป็นฟังก์ชั่นหรือไม่และถ้ามันไม่พบมันจะส่งคำเตือนเหมือนถ้าคุณมีการเรียกใช้ฟังก์ชันนั้น .
  • ภายในcl-fletและcl-labelsเพียง#'fสามารถอ้างถึงฟังก์ชั่นที่กำหนดไว้ในประเทศfเพราะ'fจะยังคงหมายถึงสัญลักษณ์ทั่วโลกf(และฟังก์ชั่นแล้วแต่จำนวนใดจะถูกเก็บไว้ในของsymbol-functionช่อง) เช่น

    (cl-flet ((car (x y) (+ x y)))
      (list #'car 'car))
    =>
    ((closure nil (x y) (+ x y)) car)
    
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.