ทำไมภาษาควรเยื้องมากกว่าเครื่องหมายที่ชัดเจนสำหรับบล็อก?


11

ฉันกำลังเรียนรู้ Haskell และฉันกำลังมองหาเครื่องมือการเยื้องอัตโนมัติ ฉันไม่ได้ดูมากนักและเรียนรู้ว่าใน Haskell (เช่นเดียวกับใน Python) การเยื้องนั้นหมายถึงบล็อก ด้วยเหตุนี้ฉันเดาว่าเป็นไปไม่ได้ที่จะสร้างเครื่องมือการจัดรูปแบบอัตโนมัติที่แข็งแกร่งเช่นเดียวกับในภาษาอื่น ๆ ในตระกูล C ที่ใช้ตัวระบุที่ชัดเจนเช่น {} (เครื่องหมายปีกกา) หรือbegin endคำหลัก

ฉันไม่สนใจภาษาที่บังคับให้ย่อหน้าเพื่อให้อ่านได้ แต่ฉันไม่สามารถเข้าใจถึงประโยชน์ของทั้งการบังคับใช้การเยื้องและมีเครื่องหมายระบุชัดเจนเพื่อให้เครื่องมืออัตโนมัติสามารถเข้าใจสิ่งที่อยู่ในบล็อกนั้น

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

เหตุใดนักออกแบบภาษาจึงเลือกการเยื้องผ่านตัวทำเครื่องหมายบล็อกอย่างชัดเจน


8
ไม่ได้คำตอบ แต่ Haskell ทำให้ช่องว่างความไวจำนวนมากตัวเลือกมากกว่าหลาม คุณสามารถใช้เครื่องหมายอัฒภาคสำหรับทุกสิ่งและห่อบล็อกด้วยเครื่องหมายปีกกาหากต้องการ ถูกต้องสมบูรณ์ตามที่เป็นอยู่let x =1; y = 2; z = 3 do { putStrLn $ show x; putStrLn $ show y; putStrLn $ show z; }สิ่งเหล่านั้นไม่จำเป็นต้องอยู่ในบรรทัดเดียวกัน
KChaloux

8
"เป็นไปไม่ได้ที่จะสร้างเครื่องมือการจัดรูปแบบอัตโนมัติ" - จริงๆแล้วไม่จำเป็นต้องใช้เครื่องมือการจัดรูปแบบอัตโนมัติใน Python เนื่องจากกฎการเยื้อง
Doc Brown

13
อืมการเพิ่มการเยื้องเป็นเครื่องหมายบล็อกที่ชัดเจน
Karl Bielefeldt

3
@ K.Gkinis: แหล่งที่ดีที่สุดสำหรับแรงจูงใจที่แท้จริงที่อยู่เบื้องหลังการตัดสินใจออกแบบภาษาคือผู้ออกแบบภาษาเอง
Robert Harvey

3
คำถามนี้ไม่ได้เป็นอัตวิสัย มันถามว่าทำไมนักออกแบบภาษาบางคนเลือกไวยากรณ์ สามารถตอบได้ หากคำถามได้ถามว่าไวยากรณ์ใดดีที่สุดมันจะเป็นอัตนัย
JacquesB

คำตอบ:


13

Guido Von Rossum

จากการสัมภาษณ์กับ Guido Van Rossumซึ่งสามารถอ่านได้เต็มรูปแบบกับ books.google.co.th (เน้นที่เหมือง):

ทางเลือกของการเยื้องสำหรับการจัดกลุ่มไม่ใช่แนวคิดใหม่ใน Python; ฉันสืบทอดสิ่งนี้จาก ABCแต่มันก็เกิดขึ้นใน Occam ซึ่งเป็นภาษาเก่ากว่า ฉันไม่รู้ว่าผู้เขียน ABC ได้รับความคิดจาก Occam หรือคิดค้นมันขึ้นมาเองหรือว่ามีบรรพบุรุษร่วมกัน แน่นอนฉันจะได้เลือกที่จะไม่ทำตามนำของเอบีซีที่ผมทำในพื้นที่อื่น ๆ (เช่นเอบีซีใช้ตัวพิมพ์ใหญ่สำหรับคำหลักภาษาและชื่อกระบวนความคิดผมไม่ได้คัดลอก) แต่ผมได้มาเช่นคุณลักษณะค่อนข้าง บิตในขณะที่ใช้เอบีซีตามที่มันดูเหมือนจะทำไปด้วยบางประเภทของการอภิปรายทั่วไปไม่มีจุดหมายในหมู่ Cผู้ใช้ในเวลาที่เกี่ยวกับตำแหน่งที่จะวางวงเล็บปีกกา

Von Rossum ได้รับแรงบันดาลใจอย่างมากจากABCและแม้ว่าเขาไม่จำเป็นต้องคัดลอกทั้งหมดการใช้การเยื้องก็ถูกเก็บไว้เพราะมันจะมีประโยชน์ในการหลีกเลี่ยงสงครามศาสนา

ฉันยังทราบดีว่ารหัสที่อ่านได้ใช้การเยื้องอย่างสมัครใจเพื่อระบุการจัดกลุ่มและฉันได้พบข้อบกพร่องเล็กน้อยในรหัสที่การเยื้องไม่เห็นด้วยกับการจัดกลุ่มวากยสัมพันธ์โดยใช้เครื่องหมายปีกกา - ผู้เขียนโปรแกรมและผู้ตรวจทานใด ๆ สันนิษฐานว่า และดังนั้นจึงไม่ได้สังเกตเห็นข้อผิดพลาด อีกครั้งเซสชันการดีบักที่ยาวนานสอนบทเรียนที่มีค่า

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

Donald E. Knuth และ Peter J. Landin

ในการสัมภาษณ์อ้างอิง Guido กล่าวถึงแนวคิดของ Don Knuth ในการใช้การเยื้อง นี้เป็นรายละเอียดในนูเยื้องอ้างค้นพบซึ่งคำพูดที่มีโครงสร้างการเขียนโปรแกรมด้วยงบโกโตะ Knuth ยังอ้างอิงถึง Peter John Landin ของภาษาการเขียนโปรแกรมอีก 700 ภาษา (ดูหัวข้อการสนทนาเกี่ยวกับการเยื้อง) Landin ออกแบบISWIMซึ่งดูเหมือนภาษาแรกที่มีการเยื้องแทนที่จะเป็นบล็อกเริ่มต้น / สิ้นสุด เอกสารเหล่านั้นเกี่ยวกับความเป็นไปได้ของการใช้การเยื้องสำหรับการจัดโครงสร้างโปรแกรมแทนที่จะเป็นข้อโต้แย้งที่แท้จริงในการทำเช่นนั้น


1.ผมคิดว่านี่คือในความเป็นจริงข้อโต้แย้งในความโปรดปรานของการมีทั้งโครงสร้างการจัดกลุ่มและการจัดรูปแบบอัตโนมัติเพื่อที่จะจับและการกู้คืนจากข้อผิดพลาดในการเขียนโปรแกรมซึ่งจะผูกพันที่จะเกิดขึ้น หากคุณทำให้การเยื้องของคุณเป็น Python บุคคลที่ดีบั๊กโค้ดของคุณจะต้องเดาว่าถูกต้องหรือไม่:

if (test(x)):
  foo(x)
  bar(x)

จะbarถูกเรียกหรือเฉพาะเมื่อการทดสอบสำเร็จหรือไม่

โครงสร้างการจัดกลุ่มเพิ่มระดับความซ้ำซ้อนที่ช่วยให้คุณเห็นข้อผิดพลาดเมื่อคุณเยื้องรหัสของคุณโดยอัตโนมัติ ใน C โค้ดเทียบเท่าสามารถเยื้องอัตโนมัติได้ดังนี้

if (test(x))
  foo(x);
bar(x);

ถ้าฉันมีไว้สำหรับbarให้อยู่ในระดับเดียวกับที่fooแล้วอัตโนมัติเยื้องขึ้นอยู่กับโครงสร้างรหัสให้ฉันเห็นว่ามีสิ่งผิดปกติที่สามารถแก้ไขได้โดยการเพิ่มวงเล็บรอบและ foobar

ในPython: ตำนานเกี่ยวกับการเยื้องมีตัวอย่างที่ไม่ดีจาก C:

/*  Warning:  bogus C code!  */

if (some condition)
        if (another condition)
                do_something(fancy);
else
        this_sucks(badluck);

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

นอกจากนี้รหัสกลางที่การเยื้องปิดใน C ก็ไม่ได้ทำให้ผ่านสาขาหลักการตรวจสอบสไตล์ทั้งหมดจะทำให้ GCC / Jenkins กรีดร้องใส่ฉัน เมื่อเร็ว ๆ นี้ฉันมีปัญหาคล้ายกับที่อธิบายไว้ข้างต้นใน Python พร้อมกับแถลงการณ์โดยการเยื้องระดับหนึ่ง บางครั้งฉันมีรหัสใน C ซึ่งเกินกว่าวงเล็บปิด แต่จากนั้นฉันกด Tab และรหัสเยื้อง "ผิด": นั่นเป็นอีกโอกาสหนึ่งที่จะเห็นข้อบกพร่อง


3
"เพื่อหลีกเลี่ยงสงครามศาสนา ... " ฉันแปลกใจว่าเหตุผลที่แท้จริงนั้นเป็นเรื่องเล็กน้อย
Robert Harvey

1
@RobertHarvey: การเน้นที่วลีนั้นคือโดย coredump ไม่ใช่โดย van Rossum มันไม่ใช่เหตุผลหลักหากคุณอ่านคำพูดของ Van Rossum ในบริบท
JacquesB

@JacquesB โปรดบอกฉันว่าบริบทใดหายไปจากเครื่องหมายคำพูดเพื่อให้ฉันสามารถแก้ไขคำตอบได้
coredump

4
ฉันไม่ได้รับความเห็นส่วนตัวจากคุณ: ถ้าคุณทำตัวเยื้องใน Python คุณก็จะมีปัญหา หากคุณขันสกรูใน C คุณมีบั๊ก หากคุณใช้การเยื้องอัตโนมัติมันจะเหมือนกันทั้งสองภาษา และถ้าคุณไม่ใช้การเยื้องอัตโนมัติข้อผิดพลาดสามารถซ่อนอยู่ใน C ในลักษณะที่เป็นไปไม่ได้ใน Python
JacquesB

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

7

นี่เป็นอัตวิสัยสูงและเป็นต้นเหตุของสงครามเพลิงหลายครั้ง อย่างไรก็ตาม:

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

Python ออกแบบและคำถามที่พบบ่อยประวัติระบุไว้อย่างชัดเจน:

ทำไมไพ ธ อนจึงใช้การเยื้องสำหรับการจัดกลุ่มคำสั่ง?

Guido van Rossum เชื่อว่าการใช้การเยื้องในการจัดกลุ่มเป็นสิ่งที่สวยงามมากและมีส่วนช่วยอย่างมากต่อความชัดเจนของโปรแกรม Python โดยเฉลี่ย คนส่วนใหญ่เรียนรู้ที่จะรักคุณสมบัตินี้หลังจากที่ในขณะ

เนื่องจากไม่มีเครื่องหมายเริ่มต้น / สิ้นสุดจึงไม่สามารถมีความขัดแย้งระหว่างการจัดกลุ่มที่ parser รับรู้และผู้อ่านของมนุษย์

เป็นความจริงที่คุณไม่สามารถสร้างเครื่องมือการเยื้องอัตโนมัติสำหรับ Python ได้ แต่นี่เป็นสิ่งที่ดี: หมายความว่าคุณไม่มีความซ้ำซ้อนในไวยากรณ์ที่คุณต้องการเครื่องมืออัตโนมัติในการปรับยอด

แท็บเทียบกับช่องว่างเป็นข้อกังวลที่ถูกต้องตามกฎหมายใน Python และแนะนำให้ไม่ผสมแท็บและช่องว่าง (สำหรับการเยื้อง) ใน codebase เดียวกัน

Python สืบทอดการเยื้องที่สำคัญจากภาษาบรรพบุรุษ ABC (ตอนนี้ล้าสมัย) ABC เป็นหนึ่งในไม่กี่ภาษาโปรแกรมที่ใช้การทดสอบการใช้งานเพื่อควบคุมการออกแบบ ดังนั้นในขณะที่การอภิปรายเกี่ยวกับไวยากรณ์มักจะมาลงความเห็นส่วนตัวและการตั้งค่าส่วนตัวการเลือกของการเยื้องสำคัญมีจริง sounder รากฐาน


6
บัญชีสองรายการละเมิด DRY ด้วย บางครั้งความซ้ำซ้อนก็เป็นคุณสมบัติหนึ่ง
coredump

3
@coredump: จริง แต่เป็นการออกแบบซ้ำซ้อนที่จงใจ ภาษาการเขียนโปรแกรมส่วนใหญ่รวมถึง Python มีความซ้ำซ้อนที่เลือกโดยเจตนาเช่นpassคำหลักที่สามารถอนุมานได้โดยอัตโนมัติ แต่การกำหนดให้ชัดเจนช่วยให้ค้นพบข้อผิดพลาด ความซ้ำซ้อนโดยไม่ตั้งใจของการมีทั้งสัญลักษณ์เริ่มต้น / สิ้นสุด (สำหรับคอมไพเลอร์) และการเยื้อง (สำหรับผู้อ่านที่เป็นมนุษย์) ดูเหมือนจะทำให้เกิดข้อผิดพลาดมากกว่าที่จับ อย่างน้อยนี่น่าจะเป็นมุมมองของ van Rossum
JacquesB

@coredump - ตอนนี้ฉันรู้แล้วว่าทำไมฉันไม่ได้เป็นนักบัญชี
JeffO

3
@coredump คุณคิดถึง COBOL PROCEDURE DIVISION.หรือเปล่า ฉันไม่สามารถบอกได้ว่าจุดDATA DIVISIONสิ้นสุดและขั้นตอนเริ่มต้นในภาษาใหม่ที่มีภาษาเหล่านี้
msw

2
@coredump: "เห็นเยื้องขัดแย้งกับสิ่งที่ฉันมีอยู่ในใจก็เพียงพอที่จะป้องกันข้อผิดพลาด" - ว่า
JacquesB

2

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


1
ฉันสามารถดูได้ว่าทำไมใครจะพิจารณาอัฒภาคและเสียงเหล็กดัด แต่มันมีประสิทธิผลน้อยกว่าหรือไม่ที่จะต้องพิมพ์อวกาศ 4/8/12 เท่า? และถ้าคุณพลาดอย่างใดอย่างหนึ่ง (เนื่องจากพวกเขามองไม่เห็น) คุณกำลังมีปัญหา
Reinstate Monica

5
นั่นเป็นเหตุผลที่คุณใช้แท็บแทนช่องว่างหรือ IDE ที่เข้าใจวิธีการแปลงแท็บเป็นบล็อกสี่ช่องว่าง
Robert Harvey

@ K.Gkinis: เยื้องไม่ได้มองไม่เห็น เฉพาะพื้นที่ว่างที่ปลายสุดของบรรทัดเท่านั้นที่มองไม่เห็น แต่สิ่งนี้ไม่สำคัญในภาษาใด ๆ เฉพาะเมื่อคุณผสมแท็บและช่องว่างคุณจะมีปัญหา ดังนั้นอย่าทำอย่างนั้น
JacquesB

@JacquesB: ปัญหาเกี่ยวกับการมองเห็น / การเยื้องของการเยื้องคือในฐานะมนุษย์คุณมักไม่สามารถบอกความแตกต่างระหว่างช่องว่างกับแท็บได้ในขณะที่คอมพิวเตอร์สามารถทำได้บ่อยครั้ง ดังนั้นในขณะที่มองเห็นการเยื้อง แต่วิธีที่คอมพิวเตอร์ตีความการเยื้องอาจแตกต่างกัน นั่นเป็นปัญหาที่แท้จริง: เมื่อคอมพิวเตอร์ปฏิบัติต่อตัวละครที่มองไม่เห็นต่างไปจากมนุษย์ มนุษย์วัดการเยื้องเป็นระยะทางบนหน้าจอคอมพิวเตอร์อาจวัดได้ตามจำนวนตัวอักษรที่แท้จริง นั่นคือส่วนที่มองไม่เห็น
Bryan Oakley

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