“ และ” vs“ เมื่อ” สำหรับเงื่อนไข


13

นี่คือการติดตามความคิดเห็นของคำตอบนี้ บิตของรหัสต่อไปนี้ดูเหมือนจะเทียบเท่า:

(and a b)

(when a b)

แน่นอนandช่วยให้คุณใส่เงื่อนไขเพิ่มเติม: (and a b c d)หมายถึง(when (and a b c) d)

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

ฉันไม่มีแหล่งที่มาของ Emacs andเป็นฟังก์ชั่น C; whenเป็นแมโครที่ขยายไปifซึ่งตัวมันเองเป็นฟังก์ชั่น C


"แน่นอนและให้" ควร "แน่นอน" และ `ให้" แต่นั่นเป็นเพียงการเปลี่ยนแปลงตัวละคร 2 ตัวและไม่อนุญาตให้แก้ไข ไม่มีการแทนที่
ฮาร์วีย์

คำตอบ:


18

TL; DR: whenเกี่ยวกับผลข้างเคียงandมีไว้สำหรับนิพจน์บูลีนบริสุทธิ์

ตามที่คุณสังเกตเห็นandและwhenแตกต่างในรูปแบบไวยากรณ์ แต่จะเทียบเท่ากันทั้งหมด

ความแตกต่างของวากยสัมพันธ์เป็นสิ่งสำคัญมากแม้ว่า: whenล้อมprognรอบทั้งหมด แต่รูปแบบการโต้แย้งครั้งแรก prognมันเป็นคุณสมบัติที่จำเป็นอย่างยิ่ง: มันประเมินผลทั้งหมด แต่รูปแบบสุดท้ายของร่างกายสำหรับผลข้างเคียงของพวกเขาเท่านั้นโดยละทิ้งสิ่งที่พวกเขากลับมา

เช่นwhenนี้เป็นรูปแบบที่จำเป็นเช่นกัน: มันมีจุดประสงค์หลักคือการห่อรูปแบบที่มีผลข้างเคียงเพราะเฉพาะค่าของรูปแบบสุดท้ายเท่านั้นที่สำคัญสำหรับร่างกาย

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

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

ดังนั้นสิ่งเหล่านี้จึงเป็นรูปแบบที่ไม่ดี:

;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
                    (file-exists-p (buffer-file-name buffer)))))
  ...)

;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))

และสิ่งเหล่านี้ดี

(let ((use-buffer (and (buffer-live-p buffer)
                       (file-exists-p (buffer-file-name buffer)))))
  ...)

(when (buffer-file-name buffer)
 (write-region nil nil (buffer-file-name buffer)))

ฉันรู้ว่าบางคนไม่เห็นด้วยกับเรื่องนี้และใช้andเพื่อป้องกันผลข้างเคียงอย่างมีความสุขแต่ฉันคิดว่านี่เป็นสไตล์ที่ไม่ดีจริงๆ เรามีรูปแบบที่แตกต่างกันเหล่านี้สำหรับเหตุผล: ไวยากรณ์ที่สำคัญ หากไม่เป็นเช่นนั้นเราทุกคนจะเคยใช้ifซึ่งเป็นรูปแบบเงื่อนไขเดียวที่คุณต้องการใน Emacs Lisp ความหมาย ทุกรูปแบบบูลีนและเงื่อนไขอื่น ๆ ifที่สามารถเขียนได้ในแง่ของ


2
IMO (กล่าวคือในการใช้งานผมสไตล์) andเป็นเรื่องเกี่ยวกับการดูแลเกี่ยวกับค่าตอบแทน ไม่จำเป็นต้องเกี่ยวกับการใช้ผลข้างเคียง andถ้าใส่ใจโปรแกรมของฉันเกี่ยวกับค่าตอบแทนแล้วฉันจะใช้ ถ้ามันไม่ได้ใช้whenแล้ว IOW ผมใช้when เฉพาะสำหรับผลข้างเคียง แต่ฉันอาจรวมทั้งใช้prognในหนึ่งใน args andไป มันเป็นเรื่องไม่ว่าจะเป็นเรื่องค่าตอบแทนที่ไม่เกี่ยวกับว่ามันอยู่คนเดียวเรื่อง
ดึง

5
andไม่ใช่ฟังก์ชั่นใน Lisp ที่ฉันรู้จัก ใน Emacs Lisp มันเป็นรูปแบบพิเศษใน Common LISP เป็นแมโครเพียงเพราะคาดว่าจะมีพฤติกรรมการลัดวงจร (เป็นไปไม่ได้ที่จะบรรลุด้วยฟังก์ชั่น
Mark Karpov

2
@ lunaryorn ใช่มันไม่เกี่ยวข้องกันจริงๆ แต่มันเป็นเรื่องจริงดังนั้นฉันคิดว่ามันไม่ถูกต้องที่จะเขียนนั่นandคือฟังก์ชั่นเมื่อมันไม่ได้ ไม่สำคัญว่าคำถามนี้เกี่ยวข้องกับความจริงเพียงใดเราควรใช้คำที่ถูกต้องเสมอนั่นคือทั้งหมด
Mark Karpov

2
ฉันไม่คิดว่า "คุณค่าของทุกรูปแบบการโต้แย้งมีความสำคัญ" สอดคล้องกับสิ่งที่ตีความ มันน่าจะแสดงออกได้ดีกว่าโดยบอกว่าไม่มีการประเมินฟอร์มใด ๆ เพื่อให้มูลค่าของมันถูกทิ้งไป
Harald Hanche-Olsen

3
ค่อนข้าง OT แต่: ความแตกต่างเป็นมากกว่าโวหารใน Lisps ที่ไม่ได้nilหมายถึงทั้งหมดของ "เท็จ", "รายการที่ว่างเปล่า", "โมฆะ", ฯลฯ ตัวอย่างเช่นใน Scheme และแร็กเก็ตผลที่ไม่ใช่ความจริงของwhenคือvoid(คือ "ไม่มีความหมาย") ในขณะที่andมันเป็น#f("เท็จ") แม้ว่านี่จะเป็น N / A สำหรับ Elisp แต่มันเป็นสิ่งที่คนทั่วไป Lisp อาจพิจารณา
Greg Hendershott

4

ผมขอเริ่มด้วยการบอกอย่างนั้น(and a b)และ(when a b)ในตัวอย่างของคุณทำสิ่งเดียวกัน: อันดับแรกaถูกประเมิน bได้รับการประเมินถ้าaเป็นจริง #

แต่ andและwhenใช้สำหรับสิ่งต่าง ๆ

  • คุณจะใช้(and a b)เพื่อส่งกลับ# จริงถ้าทั้งสองและเป็นจริง# (หรือไม่ใช่ - ศูนย์); และอื่น ๆabnil

  • คุณจะใช้(when a b)หรือแก้ไขให้ถูกต้องมากขึ้น

    (when a
       ;; do something like b
       )

    เมื่อคุณต้องการ "B" รหัสในการดำเนินการและถ้าหากaเป็นจริง #


นี่คือตัวอย่างที่คุณใช้whenและandร่วมกัน:

(when (and a b)
   (do-c))

ข้างต้นฟังก์ชั่นdo-cที่เรียกว่าเฉพาะถ้าทั้งสองaและbเป็นจริง #


เอกสารอ้างอิงเพื่อการศึกษา

# การอ้างอิงทั้งหมดถึงTrueอ้างถึง Boolean TRUE


3
andไม่ส่งคืนtถ้าอาร์กิวเมนต์ทั้งหมดเป็นแบบไม่ใช่ศูนย์ แต่จะมีค่าของอาร์กิวเมนต์ล่าสุด
ชื่อผู้ใช้ที่มีความหมาย

1
โดยtฉันหมายถึงบูลีน TRUE หรือไม่มี - ขอบคุณฉันจะชี้แจงในคำตอบของฉัน
Kaushal Modi

ฉันไม่คิดว่าคำตอบของคุณจะไปไกลเกินกว่าที่ฉันได้กล่าวไปแล้วในคำถาม ฉันรู้ว่าทั้งสองทำอะไรและตัวอย่างสุดท้ายที่คุณให้ปรากฏในคำถามของฉัน ( (when (and a b) c)) นอกจากนี้ส่วนเกี่ยวกับวิธีการandและwhenแนะนำว่าจริง ๆ แล้วเป็นวิธีการใช้งานทั่วไป แต่พื้นฐานที่สำคัญสำหรับคำถามนี้คือความจริงที่ว่าฉันมักจะเห็นพวกเขาใช้แตกต่างกัน (ดูตัวอย่างคำตอบที่ฉันเชื่อมโยงกับคำถามของฉัน)
Clément

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

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