ฉันควรใช้ progn เมื่อใด / เพราะเหตุใด


19

ฉันเห็นว่ามีprognการใช้งานค่อนข้างมากเมื่อฉันเรียกดูไฟล์กำหนดค่าของผู้ใช้ Emac ที่มีประสบการณ์ ฉันพบคำอธิบายที่ดีของprognสิ่งนี้ แต่สิ่งที่ฉันอยากรู้จริงๆคือประโยชน์ของการใช้ฟังก์ชั่นนี้คืออะไร? ยกตัวอย่างเช่นตัวอย่างนี้ (นำมาจากการกำหนดค่าของ Sacha Chua ):

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

มีความแตกต่างที่สำคัญระหว่างการกำหนดค่าข้างต้นและสิ่งนี้หรือไม่?

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t))

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


7
ในกรณีพิเศษนี้จะไม่มีความแตกต่าง: use-packageจะprognล้อมรอบของคุณ: รูปแบบการกำหนดค่าถ้ามันหายไป ลองทำดู: คุณสามารถวางจุดท้าย(use-package ...)และเรียกM-x pp-macroexpand-last-sexpเพื่อดูว่าแมโครขยายได้อย่างไร คุณจะเห็นว่ามันเหมือนกันสำหรับสองตัวอย่างนี้
ลูกัส

ตัวอย่างที่prognต้องการ: emacs.stackexchange.com/questions/39172/…
npostavs

คำตอบ:


11

prognโดยทั่วไปจะใช้เมื่อจัดการกับมาโคร บางมาโคร ( use-packageเป็นแมโครผมที่ผ่านการตรวจสอบ) ยอมรับเพียง 1 รูปแบบที่คนอื่น ๆ ใช้รูปแบบที่เหลืออยู่ทั้งหมด

progn ใช้ในกรณีก่อนหน้านี้เพื่อเปลี่ยนลำดับของแบบฟอร์มให้เป็นแบบฟอร์มเดียว

ในตัวอย่างของคุณเป็นคนแรกที่ใช้prognและทำให้มี1 รูปแบบ:configหลังจากที่ ในครั้งที่สองมี3 รูปแบบ หากuse-packageมาโครคาดว่าจะมี 1 รูปแบบ:configเท่านั้นซึ่งจะทำให้เกิดข้อผิดพลาด

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


15
มันไม่มีส่วนเกี่ยวข้องกับมาโครจริงๆ ฟังก์ชั่นและมาโครบางตัวมีสิ่งที่เรียกว่า "โดยนัยprogn" ซึ่งหมายความว่าพวกเขายอมรับจำนวน sexps ใด ๆ เป็นอาร์กิวเมนต์ที่แยกต่างหากและประเมินตามลำดับ คนอื่นทำไม่ได้และคาดว่าจะ / อนุญาตเพียงอาร์กิวเมนต์เดียวที่คุณอาจต้องการประเมินหลาย sexps ตามลำดับ นั่นคือทั้งหมดที่progn: มันช่วยให้คุณให้ sexp เดียวที่เมื่อประเมินประเมิน sexp args ไปprognตามลำดับ เปรียบเทียบกับ(if true (progn a b c)) (when true a b c)ในทั้งสองกรณีa, bและcได้รับการประเมินในลำดับ
ดึง


4
ฉันไม่เห็นด้วยว่า 99% ของกรณีการใช้งานนั้นมีไว้สำหรับมาโคร ฯลฯฟังก์ชั่นหรือมาโครใด ๆ ที่สามารถส่งผ่านprognsexp ที่มีหลายเซ็กส์ที่ได้รับการประเมินสำหรับผลข้างเคียงก่อนที่จะส่งคืนผลลัพธ์สุดท้าย มันไม่มีส่วนเกี่ยวข้องกับมาโครจริงๆ มาโคร "เป็นตัวอย่าง" ใช้ได้ การแสดงผลที่prognมีอยู่สำหรับมาโครและการใช้งาน 99% นั้นมีไว้สำหรับมาโครนั้นทำให้ IMO เข้าใจผิด prognเป็นเรื่องเกี่ยวกับการพรวนดินลำดับของการประเมินผลเป็นเดียว sexp (เพื่อให้พอดีกับข้อโต้แย้งที่คาดว่าจะได้รับ) และดังนั้นจึงเป็นเรื่องเกี่ยวกับผลข้างเคียง
ดึง

5
1. prognเปิดตัวในLisp 1.5 (ดูหัวข้อThe Feature Feature ) ในปี 1962 นานก่อนที่จะเพิ่มมาโครลงใน Lisp วัตถุประสงค์คือเพื่อประเมินนิพจน์สำหรับผลข้างเคียงของพวกเขาตามลำดับ 2. ดูprognว่าEmacsแนะนำตัวเองอย่างไรprognกับโปรแกรมเมอร์ Elisp ดูzap-to-charรหัสสำหรับกรณีการใช้งานที่ง่าย
ดึง

2
เราสามารถตกลงที่จะไม่เห็นด้วย จุดของฉันคือว่าprognมีสิ่งใดที่จะทำอะไรกับมาโคร โดยมีวัตถุประสงค์คือแน่นอน " ที่จะผ่านหลายรูปแบบเป็นรูปแบบเดียว " (คำพูดของคุณ) - ว่าจะฟังก์ชั่นหรือมาโครหรือรูปแบบพิเศษ แต่ยังรวมถึง " Eval BODY รูปแบบตามลำดับและค่าตอบแทนของคนสุดท้าย " (สตริง doc ) ตอนนี้เช่นเคย ("วันนี้" แน่นอน!) การประเมินผลที่ได้รับคำสั่งเป็นสิ่งสำคัญสำหรับผลข้างเคียงเท่านั้น กรณีการใช้งานที่ให้มา (มาโครหรือไม่) อาจหรืออาจไม่สนใจเกี่ยวกับลำดับการประเมินผล แต่นั่นไม่เกี่ยวข้อง และ Emacs Lisp ไม่ได้มีความพิเศษ แต่อย่างใดในเรื่องนี้
Drew

10

เหตุผลที่สำคัญที่สุดสำหรับprognอธิบายไว้ในบรรทัดแรกของเอกสาร progn (เน้นที่เพิ่ม):

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

ภาคผนวก:

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

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

ไม่prognเพิ่มประสิทธิภาพ?

การแยกวิเคราะห์ประสิทธิภาพเลขที่ ประสิทธิภาพการดำเนินการหมายเลข ที่ดีที่สุดมันอาจเท่ากัน แต่ไม่เคยเพิ่มประสิทธิภาพอย่างน่าอัศจรรย์

เมื่อมีการprogn ใช้ ?

... ส่วนใหญ่มักจะอยู่ภายในผ่อนคลายป้องกันและหรือหรือในนั้นเป็นส่วนหนึ่งของถ้า


ฉันไม่แน่ใจว่าทำไมมันถึงสำคัญ Emacs จะประเมินตามลำดับเสมอ
Lunaryorn

2
@lunaryorn ดูคำตอบที่อัพเดตแล้ว
ผู้ใช้ Emacs

ฉันไม่แน่ใจว่าฉันเข้าใจการแก้ไขของคุณหรือไม่ โดยปกติจะมีรูปแบบพิเศษที่มีลำดับการประเมินผลที่แตกต่างกัน (เช่นif) แต่ลำดับการประเมินปกติ (เช่นแบบฟอร์มระดับบนสุด, หน่วยงานการทำงาน ฯลฯ ) เป็นข้อความ แน่นอนว่ามันเป็นการบอกเป็นนัยprognแต่โดยปกติแล้วมันไม่ใช่สิ่งที่คุณใช้progn ในรหัสของคุณ
Lunaryorn

ฉันคิดว่าโหนด Elisp manual (elisp) Sequencingซึ่งคุณเชื่อมโยงกล่าวเอาไว้ทั้งหมด
เพรา

10

วิธีที่ดีกว่าที่จะเข้าใจในสิ่งที่prognเป็นคือโดยการเปรียบเทียบกับครอบครัว: และprog1 หรือหรือส่วนหนึ่งของชื่อย่อมาจากคำสั่งจากรายการที่มีผลให้คุณมีความสนใจใน. ในคำอื่น ๆจะกลับผลของคำสั่งที่ผ่านมามันมีในขณะที่จะกลับมาครั้งแรกและที่คล้ายกันสำหรับprog2n12prognprog1prog2

วันนี้ฟังก์ชั่นนี้ดูน่าอึดอัดใจเล็กน้อยเนื่องจากเราเรียนรู้ที่จะคาดหวังว่าโปรแกรมจะกลับมาในคำสั่งสุดท้ายหรือบอกให้ชัดเจนว่าจะส่งคืนอย่างไร ดังนั้นprog1และprog2ไม่ค่อยมีใครใช้ อย่างไรก็ตามถ้าคุณคิดเกี่ยวกับมันมันสมเหตุสมผลและนี่คือวิธี:

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

ในภาษา C-like คุณลักษณะนี้บางครั้งเรียกว่าเป็นจุดลำดับ (เช่น;และ,ตัวอย่าง) prognมีความสำคัญต่อภาษาที่เหมือนเสียงกระเพื่อมเหมือนภาษา;C มันเป็นคุณสมบัติพื้นฐานของภาษาที่ไม่สามารถแทนที่ได้อย่างง่ายดาย อย่างไรก็ตามแตกต่างจากภาษาสไตล์ C, Lisp มีแนวโน้มที่จะสร้าง abstractions เกี่ยวกับการสร้างประโยคโดยการซ่อนไวยากรณ์ของระดับล่างอย่างสมบูรณ์ และนี่อาจเป็นเหตุผลว่าทำไมคุณไม่เห็นprognใช้ทั้งหมดบ่อยครั้ง แต่เป็นหนึ่งในหน่วยการสร้างที่สำคัญเมื่อพูดถึงการสร้าง abstractions ภาษาระดับสูงขึ้น (มาโคร)

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