ความต่อเนื่องระดับเฟิร์สคลาสมีประโยชน์ในภาษาการเขียนโปรแกรมเชิงวัตถุสมัยใหม่หรือไม่?


10

การทำต่อเนื่องนั้นมีประโยชน์อย่างมากในภาษาโปรแกรมที่ใช้งานได้ (เช่นContmonad ใน Haskell) เพราะพวกมันยอมให้สัญกรณ์ง่ายและสม่ำเสมอสำหรับโค้ดสไตล์ที่จำเป็น นอกจากนี้ยังมีประโยชน์ในภาษาที่จำเป็นบางอย่างที่เก่ากว่าเพราะสามารถใช้ในการใช้คุณสมบัติภาษาที่ขาดหายไป (เช่นข้อยกเว้น coroutines, เธรดสีเขียว) แต่สำหรับภาษาเชิงวัตถุที่ทันสมัยด้วยการสนับสนุนในตัวสำหรับคุณลักษณะเหล่านี้สิ่งที่มีปากเสียงจะมีเป็นยังเพิ่มการสนับสนุนสำหรับตชั้นแรก (ไม่ว่าจะรูปแบบที่คั่นที่ทันสมัยมากขึ้นresetและshiftหรือโครงการเหมือนcall-with-current-continuation)?

มีการขัดแย้งกับการเพิ่มการสนับสนุนอื่น ๆ นอกเหนือจากประสิทธิภาพการทำงานและความซับซ้อนของการดำเนินการ?

คำตอบ:


15

ให้ Eric Lippert ตอบคำถามนี้:

คำถามที่ชัดเจนในตอนนี้คือ: ถ้า CPS ยอดเยี่ยมแล้วทำไมเราไม่ใช้มันตลอดเวลา? ทำไมนักพัฒนามืออาชีพส่วนใหญ่ไม่เคยได้ยินหรือคิดว่ามันเป็นอะไรที่โปรแกรมเมอร์ Scheme ที่บ้าทำ

ก่อนอื่นมันเป็นเรื่องยากสำหรับคนส่วนใหญ่ที่คุ้นเคยกับการคิดเกี่ยวกับรูทีนย่อยลูปลองจับได้ในที่สุดและเพื่อให้เหตุผลเกี่ยวกับผู้ได้รับมอบหมายที่ใช้ในการควบคุมการไหลในลักษณะนี้ ฉันกำลังตรวจสอบบันทึกย่อของฉันเกี่ยวกับ CPS จาก CS442 ในขณะนี้และฉันเห็นว่าในปี 1995 ฉันได้เขียนคำบรรยาย:“ ด้วยความต่อเนื่องคุณต้องยืนเรียงลำดับบนหัวของคุณและดึงตัวเองออกมาข้างใน” ศาสตราจารย์ดักแกน (*) พูดถูกต้องอย่างแน่นอน จำได้จากสองสามวันที่ผ่านมาว่าตัวอย่างเล็ก ๆ ของเราเกี่ยวกับการแปลง CPS ของ C # expression M (B () (C (): C (): D ()) เกี่ยวข้องกับสี่ lambdas ไม่ใช่ทุกคนที่เก่งในการอ่านโค้ดที่ใช้ฟังก์ชันลำดับสูงกว่า มันกำหนดภาระการรับรู้ที่มีขนาดใหญ่

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

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

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

จำสิ่งที่ฉันพูดเกี่ยวกับข้อดีข้อเสียของ CPS ได้หรือไม่

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

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

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

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

รูปแบบการส่งต่อที่มีประสิทธิภาพใช่ แต่ต้องมีวิธีที่ดีกว่าในการใช้พลังนั้นให้ดีกว่าโค้ดด้านบน

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


5
มันเป็นมูลค่า noting ว่าถ้านามสกุลภาษาของคุณสนับสนุนไวยากรณ์เช่นแมโครแล้วตกลายเป็นห่างไกลที่มีประโยชน์มากขึ้นเพราะคุณสามารถซ่อนกลไกสำหรับการดำเนินการต่างๆของการควบคุมการไหลที่น่าสนใจภายในส่วนขยายไวยากรณ์ ซึ่งโดยทั่วไปแล้ววิธี "รอคอย" ทำงานอยู่แล้วมันเป็นเพียงการกำหนดในภาษาเนื่องจาก C # ไม่ได้มีเครื่องมือในการกำหนดส่วนขยายของไวยากรณ์เหล่านั้นด้วยตัวคุณเอง
แจ็ค

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

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