เมื่อใดที่จะอ้างคำแลมบ์ดาที่คมชัด?


30

ถาม:เมื่อใดถ้าเคยจะมีประโยชน์กับการเสนอราคาที่คมชัดlambdaและถ้าเป็นไปไม่ได้เราจะไม่เสนอราคาที่คมชัดเมื่อlambdaใด

คนใช้lambdas ในสามวิธี:

  1. ธรรมดา: (lambda (x) x)
  2. ที่ยกมา: '(lambda (x) x)
  3. คมชัดที่ยกมา: #'(lambda (x) x)

เธรด SO นี้กล่าวถึงสามประเภทเธรด SO นี้อธิบายถึงสาเหตุที่ไม่อ้างถึง (NB: not -quote quote ) lambdas และเธรด SOนี้ยังกล่าวถึงความแตกต่างระหว่างการอ้างถึงและการอ้างอิงที่คมชัด

ตอนนี้โหนดแบบแมนนวลในฟังก์ชั่นที่ไม่ระบุชื่อและ docstring เพื่อlambdaทราบว่าlambdaเป็นข้อความที่อ้างถึง:

การเรียกแบบฟอร์ม(lambda ARGS DOCSTRING INTERACTIVE BODY)เป็นการอ้างตนเอง ผลของการประเมินแลมบ์ดาแสดงออกคือการแสดงออกของตัวเอง แลมบ์ดานิพจน์นั้นอาจถูกมองว่าเป็นฟังก์ชัน ...

ดังนั้นจึงปรากฏว่า(lambda (x) x)และ#'(lambda (x) x)เทียบเท่า แต่'(lambda (x) x)ไม่ใช่ (ที่สำคัญที่สุดคือเมื่อรวบรวมไบต์)

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

  • การอ้างความคมชัดเป็นlambdaเพียงตัวเลือกโวหารหรือมีสถานการณ์ที่การอ้างอิงที่คมชัดนั้นมีประโยชน์จริงหรือไม่?
  • มีสถานการณ์ใดบ้างที่เราจะต้องไม่อ้างคำพูดที่แหลมคมกlambda. นั่นคือเมื่อทำเช่นนั้นจะเปลี่ยนความหมายของรหัสหรือไม่?

คำตอบ:


28

กาลครั้งหนึ่งใบเสนอราคาที่คมชัดเป็นสิ่งจำเป็นสำหรับลูกแกะตอนนี้ก็ไม่เป็นเช่นนั้นอีกต่อไป

ดังนั้นปรากฏว่า (lambda (x) x) และ # '(lambda (x) x) มีค่าเท่ากัน แต่' (lambda (x) x) ไม่ได้ (ที่สำคัญที่สุดคือเมื่อรวบรวมไบต์)

ใช่. ในความเป็นจริงทั้งสองอย่างแรกเหมือนกันอย่างสมบูรณ์เมื่อประเมิน ตามที่อธิบายไว้ในหน้าคู่มือที่คุณเชื่อมโยง:

แบบฟอร์มต่อไปนี้เทียบเท่าทั้งหมด:

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

นอกเหนือจากการพยายามสนับสนุนเวอร์ชันของ Emacs เมื่อสองทศวรรษที่ผ่านมาไม่มีเหตุผลที่จะเสนอราคาแลมบ์ดาได้

ดังนั้นอย่า


ในฐานะ sidenote:

  • การอ้างถึงแลมบ์ดาอย่างยากลำบาก (ด้วย') จะสร้างความแตกต่างป้องกันการรวบรวมไบต์ ฉันไม่สามารถนึกถึงสถานการณ์ที่มีประโยชน์ แต่ใครจะรู้

  • Backtic เป็นคำพูดเดียวที่มีประโยชน์อย่างแท้จริงกับ lambdas แต่ถ้าคุณไม่ได้ใช้การเชื่อมศัพท์ด้วยเหตุผลบางประการ


พิจารณาเพิ่มลิงค์ไปยังส่วนฟังก์ชั่นที่ไม่ระบุชื่อของคู่มือซึ่งมีตัวอย่างที่อธิบายถึงผลกระทบของการอ้างถึงการรวบรวมไบต์
Constantine

@ คอนสแตนตินทำ ฉันขี้เกียจเพราะฉันโทรศัพท์และ OP ก็เชื่อมโยงมันแล้ว
Malabarba

คุณสามารถอธิบายสิ่งที่คุณหมายถึงเกี่ยวกับการไม่ใช้การเชื่อมคำศัพท์และ backtick? ขอบคุณ
coredump

@coredump ด้วยการเชื่อมโยงแบบไดนามิกวิธีเดียวที่จะทำให้ตัวแปรภายนอกสามารถเข้าถึงได้ภายในแลมบ์ดาคือการสร้างแลมบ์ดาด้วยตนเองเป็นรายการที่มีตัวแปรอยู่ภายใน Backtics นั้นดีต่อสิ่งนั้น
Malabarba

BTW ฉันไม่คิดว่า "กาลครั้งหนึ่ง" จะนำไปใช้จริง ๆ : เมื่อฉันตรวจสอบเรื่องนี้ในประวัติศาสตร์การแก้ไขฉันพบว่าlambdaมีการกำหนดเป็นแมโครที่เพิ่มfunctionสำหรับหลังเป็นไปได้ IOW ถ้า#'มีความจำเป็นในบางจุดมันเป็นรหัสพัฒนาเร็วมาก ไม่แน่ใจว่าจำเป็นใน Emacs-18 แล้ว
สเตฟาน

5

เนื่องจากlambdaไม่ได้ทำให้รู้สึกใด ๆ เมื่อมันไม่ได้ยกมารุ่นล่าสุดของ Emacs เสียงกระเพื่อมติดตาม (ANSI) ธรรมดาชัดในการตีความ unquoted เป็น(lambda...) #'(lambda...)สัญกรณ์ทั้งสองนั้นเกือบจะเทียบเท่ากันหมด (ยกเว้นภายในโครงสร้างที่ยกมา)

ไม่ว่าจะชอบ(lambda...)หรือ#'(lambda...)เป็นเรื่องของสไตล์อย่างหมดจด บางคนชอบรูปแบบเปล่าซึ่งหลีกเลี่ยงเสียงวากยสัมพันธ์ในขณะที่คนอื่น (รวมถึงตัวเอง) ชอบแบบฟอร์มที่ยกมา


สิ่งนี้ขัดแย้งกับคู่มือ elisp: "ใน Emacs Lisp รายการดังกล่าวเป็นนิพจน์ที่ถูกต้องซึ่งประเมินผลเป็นวัตถุฟังก์ชัน"
djechlin

8
"รุ่นล่าสุด" เช่นเดียวกับใน "รุ่นที่วางจำหน่ายหลังปี 1990 หรือมากกว่านั้น" ;-)
Stefan

0

การเพิ่มประวัติเพิ่มเติมเล็กน้อยเนื่องจากเห็นว่ามรดกทางประวัติศาสตร์ # # (แลมบ์ดา ... ) หรือไม่

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=4290แนะนำว่า:

เริ่มต้นด้วย Emacs 22 lambdaรูปแบบคือไบต์รวบรวมเมื่อมันถูกนำมาใช้เป็นฟังก์ชั่นโดยไม่คำนึงว่ามันจะนำหน้าด้วยหรือfunction #'ด้วย Emacs เวอร์ชั่นก่อน 22 คุณจะต้องใช้อย่างชัดเจน#' หรือfunctionถ้าคุณต้องการให้แบบฟอร์มรวบรวมเป็นไบต์

ฉันไม่รู้เกี่ยวกับ byte-compiler แต่ฉันเห็นได้ว่าอย่างน้อยก็ย้อนกลับไปเมื่อปี 1993 lambdaมาโครเองก็คืน(function (lambda ...))ฟอร์ม

https://www.iro.umontreal.ca/~monnier/hopl-4-emacs-lisp.pdfก็พูดว่า:

น่าสนใจ (ไม่เหมือน MacLisp) lambdaไม่ได้เป็นส่วนหนึ่งของภาษา Elisp ในทางเทคนิคจนกระทั่งราวปี 1991 เมื่อมันถูกเพิ่มเป็นแมโครในช่วงแรกของการพัฒนา Emacs-19 ใน Emacs-18 ฟังก์ชันนิรนามถูกเขียนเป็นค่าที่ยกมาของแบบฟอร์ม:

'(lambda (..ARGS..) ..BODY..)

แม้ว่าlambdaแมโครจะไม่จำเป็นต้องอ้างถึงเป็นเวลาเกือบ 30 ปีแล้ว แต่ในหลายกรณีของการฝึกฝนนี้ยังคงเกิดขึ้นในรหัส Elisp แม้ว่ามันจะป้องกันการรวบรวมไบต์ของร่างกาย ค่อนข้างเกี่ยวข้องกันเฉพาะในปี 1993 เท่านั้นที่ Lucid Emacs 19.8 นำเข้า#'...ผู้อ่าน(function ...)จาก MacLisp Emacs ตามหลังปี


0

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

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
             (let ((my-variable "Random"))
               (message ,my-variable)))))

M-x [RET] eval-buffer เอาท์พุท "สุ่มเก่า"

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall (lambda()
             (let ((my-variable "Random"))
               (message my-variable)))))

M-x [RET] eval-buffer เอาท์พุท "สุ่ม"

ตัวอย่างที่สามคือการรวมตัวแปรกลางและตัวแปรโลคัล

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
              (let ((my-variable "Random"))
                (message my-variable)
                (message ,my-variable)))))

M-x [RET] eval-buffer เอาท์พุต "สุ่ม" "สุ่มเก่า"


@npostavs ที่ไม่ได้จุดด้วยตัวอย่างของฉัน แต่ฉันปรับเปลี่ยนตัวอย่างของฉันที่จะหลีกเลี่ยงการปฏิบัติที่ไม่ดีเช่นกัน
cjohansson

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