การออกแบบขนาดใหญ่ใน Haskell [ปิด]


565

เป็นวิธีที่ดีในการออกแบบ / โครงสร้างโปรแกรมการทำงานขนาดใหญ่โดยเฉพาะใน Haskell อะไร

ฉันได้ผ่านบทเรียนมากมาย (เขียนโครงการด้วยตัวเองเป็นที่ชื่นชอบกับ Real World Haskell ในไม่ช้า) - แต่โปรแกรมส่วนใหญ่มีขนาดค่อนข้างเล็กและมีวัตถุประสงค์เดียว นอกจากนี้ฉันไม่คิดว่าพวกเขาบางคนจะสง่างามเป็นพิเศษ (ตัวอย่างเช่นตารางการค้นหาที่กว้างใหญ่ใน WYAS)

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

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

มีวรรณกรรมที่เทียบเท่ากับ Haskell ไหม สวนสัตว์ของโครงสร้างการควบคุมที่แปลกใหม่มีให้ใช้งานในการเขียนโปรแกรมการทำงานอย่างไร (monads, arrow, applicative และอื่น ๆ ) ที่ใช้งานได้ดีที่สุดสำหรับจุดประสงค์นี้ คุณสามารถแนะนำวิธีปฏิบัติที่ดีที่สุดได้อย่างไร

ขอบคุณ!

แก้ไข (นี่คือการติดตามคำตอบของ Don Stewart):

@dons ที่กล่าวถึง: "Monads จับภาพการออกแบบสถาปัตยกรรมที่สำคัญในประเภทต่างๆ"

ฉันเดาว่าคำถามของฉันคือ: เราจะคิดอย่างไรเกี่ยวกับการออกแบบสถาปัตยกรรมที่สำคัญในภาษาที่ใช้งานได้จริง

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

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

สไลด์ที่เขาเชื่อมโยงมีสิ่งที่เราต้องการ bullet: "สำนวนสำหรับการทำแผนที่การออกแบบลงในประเภท / ฟังก์ชั่น / คลาส / monads" สำนวนคืออะไร? :)


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

18
@Chaos แต่ Haskell บังคับไร้สัญชาติโดยปริยายคุณไม่มีทางเลือกและต้องทำงานอย่างหนักเพื่อแนะนำสถานะ (เพื่อทำลายการรวมตัวกัน) ใน Haskell :-)
Don Stewart

7
@ChaosPandion: ฉันไม่เห็นด้วยในทางทฤษฎี แน่นอนในภาษาที่จำเป็น (หรือฟังก์ชั่นที่ออกแบบมาเพื่อการส่งข้อความ) นั่นอาจเป็นสิ่งที่ฉันต้องการ แต่ Haskell มีวิธีอื่นในการจัดการกับรัฐและบางทีพวกเขาก็ให้ฉันได้รับผลประโยชน์ที่ 'บริสุทธิ์' มากขึ้น
Dan

1
ฉันเขียนเกี่ยวกับเรื่องนี้ภายใต้ "แนวทางการออกแบบ" ในเอกสารนี้: community.haskell.org/~ndm/downloads/ …
Neil Mitchell

5
@ Jonharrop อย่าลืมว่าในขณะที่ MLOC นั้นเป็นตัวชี้วัดที่ดีเมื่อคุณเปรียบเทียบโปรเจ็กต์ในภาษาที่คล้ายกันมันไม่สมเหตุสมผลเลยสำหรับการเปรียบเทียบข้ามภาษาโดยเฉพาะอย่างยิ่งกับภาษาเช่น Haskell ซึ่งการใช้รหัสซ้ำ เทียบกับบางภาษา
Tair

คำตอบ:


519

ฉันพูดถึงเรื่องนี้เล็กน้อยในโครงการวิศวกรรมขนาดใหญ่ใน Haskellและในการออกแบบและการนำ XMonad มาใช้ วิศวกรรมในวงกว้างนั้นเกี่ยวกับการจัดการความซับซ้อน กลไกการสร้างรหัสหลักใน Haskell สำหรับการจัดการความซับซ้อน ได้แก่ :

ระบบประเภท

  • ใช้ระบบพิมพ์เพื่อบังคับใช้ abstractions ทำให้การโต้ตอบง่ายขึ้น
  • บังคับใช้ค่าคงที่คีย์ผ่านประเภท
    • (เช่นว่าค่าบางอย่างไม่สามารถหนีออกจากขอบเขตได้)
    • รหัสที่แน่นอนไม่มี IO ไม่ได้สัมผัสกับดิสก์
  • บังคับใช้ความปลอดภัย: ข้อยกเว้นที่เลือก (อาจเป็น / อาจเป็นได้) หลีกเลี่ยงแนวคิดการผสม (Word, Int, Address)
  • โครงสร้างข้อมูลที่ดี (เช่นซิป) สามารถทำให้การทดสอบบางคลาสไม่มีความจำเป็นเนื่องจากพวกเขาแยกแยะข้อผิดพลาดนอกขอบเขตเช่นแบบคงที่

ผู้สร้างโปรไฟล์

  • แสดงหลักฐานที่เป็นรูปธรรมเกี่ยวกับฮีปและโปรไฟล์ของโปรแกรม
  • โดยเฉพาะอย่างยิ่งการทำโปรไฟล์ฮีปเป็นวิธีที่ดีที่สุดเพื่อให้แน่ใจว่าไม่มีการใช้หน่วยความจำที่ไม่จำเป็น

ความบริสุทธิ์

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

การทดสอบ

  • QuickCheck + Haskell Code ครอบคลุมเพื่อให้แน่ใจว่าคุณกำลังทดสอบสิ่งที่คุณไม่สามารถตรวจสอบกับประเภท
  • GHC + RTS นั้นยอดเยี่ยมสำหรับการดูว่าคุณใช้เวลาทำ GC มากเกินไปหรือไม่
  • QuickCheck ยังสามารถช่วยคุณระบุ API แบบ orthogonal ที่สะอาดสำหรับโมดูลของคุณ หากคุณสมบัติของรหัสของคุณนั้นยากที่จะระบุพวกเขาอาจจะซับซ้อนเกินไป ทำการรีแฟคเตอร์ใหม่จนกว่าคุณจะมีชุดคุณสมบัติที่สะอาดซึ่งสามารถทดสอบโค้ดของคุณซึ่งสามารถเขียนได้ดี จากนั้นรหัสก็อาจถูกออกแบบมาอย่างดีเช่นกัน

Monads สำหรับโครงสร้าง

  • Monads จับการออกแบบสถาปัตยกรรมที่สำคัญในประเภท (รหัสนี้เข้าถึงฮาร์ดแวร์รหัสนี้เป็นเซสชั่นผู้ใช้คนเดียว ฯลฯ )
  • เช่น X monad ใน xmonad รวบรวมการออกแบบได้อย่างแม่นยำสำหรับสถานะที่มองเห็นได้ในองค์ประกอบของระบบ

พิมพ์คลาสและประเภทที่มีอยู่

  • ใช้คลาสของประเภทเพื่อให้สิ่งที่เป็นนามธรรม: ซ่อนการใช้งานที่อยู่เบื้องหลังส่วนต่อประสาน polymorphic

เห็นพ้องด้วยและขนาน

  • แอบparเข้าไปในโปรแกรมของคุณเพื่อเอาชนะการแข่งขันด้วยคู่ขนานที่เรียบง่าย

ปรับปรุงโครงสร้าง

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

ใช้ FFI อย่างชาญฉลาด

  • FFI ทำให้การเล่นกับรหัสต่างประเทศง่ายขึ้น แต่รหัสต่างประเทศนั้นอาจเป็นอันตรายได้
  • ระมัดระวังในสมมติฐานเกี่ยวกับรูปร่างของข้อมูลที่ส่งคืน

การเขียนโปรแกรม Meta

  • เทมเพลต Haskell หรือยาสามัญทั่วไปสามารถลบหม้อไอน้ำได้

บรรจุภัณฑ์และการจัดจำหน่าย

  • ใช้พันธมิตร อย่าม้วนระบบสร้างของคุณเอง (แก้ไข: จริงๆแล้วคุณอาจต้องการใช้สแต็กตอนนี้เพื่อเริ่มต้น)
  • ใช้ Haddock สำหรับเอกสาร API ที่ดี
  • เครื่องมือต่าง ๆ เช่นgraphmodสามารถแสดงโครงสร้างโมดูลของคุณได้
  • พึ่งพาไลบรารีและเครื่องมือเวอร์ชันแพลตฟอร์ม Haskell หากเป็นไปได้ มันเป็นฐานที่มั่นคง (แก้ไข: อีกครั้งในวันนี้คุณอาจต้องการใช้Stackเพื่อสร้างฐานที่มั่นคงและทำงานอยู่)

คำเตือน

  • ใช้-Wallเพื่อให้รหัสของคุณสะอาดปราศจากกลิ่น คุณอาจดู Agda, Isabelle หรือ Catch เพื่อความมั่นใจยิ่งขึ้น สำหรับการตรวจสอบเหมือนผ้าสำลีดูhlintที่ดีซึ่งจะแนะนำการปรับปรุง

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

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


8
ขอบคุณดอนคำตอบของคุณยอดเยี่ยม - ทั้งหมดนี้เป็นแนวทางที่มีค่าและฉันจะอ้างอิงพวกเขาเป็นประจำ ฉันเดาว่าคำถามของฉันจะเกิดขึ้นก่อนที่จะมีใครต้องการสิ่งนี้ สิ่งที่ฉันอยากรู้คือ "สำนวนสำหรับการทำแผนที่การออกแบบลงในประเภท / ฟังก์ชั่น / ชั้นเรียน / พระ" ... ฉันสามารถลองคิดค้นของตัวเอง แต่ฉันหวังว่าอาจจะมีชุดของการปฏิบัติที่ดีที่สุดกลั่นที่ไหนสักแห่ง - หรือถ้าไม่แนะนำให้ใช้รหัสที่มีโครงสร้างอย่างดีเพื่ออ่านระบบขนาดใหญ่ (เทียบกับพูดไลบรารีที่เน้น) ฉันแก้ไขโพสต์เพื่อถามคำถามเดียวกันนี้โดยตรง
Dan

6
ฉันได้เพิ่มข้อความเกี่ยวกับการย่อยสลายของการออกแบบในโมดูล เป้าหมายของคุณคือการระบุฟังก์ชั่นที่เกี่ยวข้องกับเหตุผลในโมดูลที่มีส่วนต่อประสานที่โปร่งใสแบบอ้างอิงกับส่วนอื่น ๆ ของระบบและใช้ชนิดข้อมูลที่ใช้งานได้จริงโดยเร็วที่สุดเท่าที่จะทำได้เพื่อสร้างแบบจำลองโลกภายนอกอย่างปลอดภัย เอกสารการออกแบบ xmonad ครอบคลุมเนื้อหามากมาย: xmonad.wordpress.com/2009/09/09/…
Don Stewart

3
ฉันพยายามดาวน์โหลดสไลด์จากโครงการวิศวกรรมขนาดใหญ่ใน Haskellคุย แต่ลิงค์ดูเหมือนจะเสีย นี่คือหนึ่งในการทำงาน: galois.com/~dons/talks/dons-londonhug-decade.pdf
mik01aj

3
ฉันจัดการเพื่อพบลิงค์ดาวน์โหลดใหม่นี้: pau-za.cz/data/2/sprava.pdf
Riccardo T.

3
@ Heath แม้ว่าลิงก์ดาวน์โหลดที่หน้าฉันพูดถึงในความคิดเห็นก่อนหน้านี้ไม่ทำงานดูเหมือนว่าภาพนิ่งยังสามารถดูได้ใน scribd: scribd.com/doc/19503176/The-Design-and-Implementation-of -xmonad
Riccardo T.

118

Don ให้รายละเอียดส่วนใหญ่กับคุณข้างต้น แต่นี่คือสองเซ็นต์ของฉันจากการทำโปรแกรมที่มีชื่อเสียงมาก ๆ อย่าง system daemons ใน Haskell

  1. ในท้ายที่สุดคุณอาศัยอยู่ในกองหม้อแปลง monad ที่ด้านล่างคือ IO ข้างต้นนั้นทุกโมดูลที่สำคัญ (ในแง่นามธรรมไม่ใช่ความรู้สึกโมดูลในไฟล์) แผนที่สถานะที่จำเป็นของมันลงในเลเยอร์ในสแต็กที่ ดังนั้นถ้าคุณมีรหัสการเชื่อมต่อฐานข้อมูลของคุณถูกซ่อนอยู่ในโมดูลคุณเขียนมันทั้งหมดให้อยู่ในประเภท MonadReader Connection m => ... -> m ... แล้วฟังก์ชั่นฐานข้อมูลของคุณสามารถรับการเชื่อมต่อได้โดยไม่ต้องใช้หน้าที่อื่น โมดูลจะต้องตระหนักถึงการดำรงอยู่ของมัน คุณอาจจบลงด้วยเลเยอร์หนึ่งที่เชื่อมต่อฐานข้อมูลของคุณอีกหนึ่งการกำหนดค่าของคุณหนึ่งในสาม semaphores และ mvars ต่างๆของคุณสำหรับการแก้ปัญหาความขนานและการซิงโครไนซ์ไฟล์บันทึกอื่นของคุณจัดการ ฯลฯ

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

ภาคผนวก (แยกจากความคิดเห็น; ขอบคุณLii & liminalisht ) -
การสนทนาเพิ่มเติมเกี่ยวกับวิธีที่แตกต่างกันในการแบ่งโปรแกรมขนาดใหญ่เป็น monads ในกองซ้อน:

เบ็นโคลเลร่าให้คำแนะนำที่ดีเกี่ยวกับหัวข้อนี้และไบรอันเฮิร์ตพูดถึงวิธีแก้ปัญหาของliftการกระทำที่เป็นเอกเทศใน Monadic ที่กำหนดเองของคุณ George Wilsonแสดงวิธีใช้mtlในการเขียนโค้ดที่ทำงานกับ monad ใด ๆ ที่ใช้ typeclasses ที่ต้องการแทนที่จะเป็น monad แบบกำหนดเองของคุณ Carlo Hamalainenเขียนบันทึกย่อสั้น ๆ ที่เป็นประโยชน์สรุปการพูดคุยของจอร์จ


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

6
@Lii Ben Koleraให้คำแนะนำที่เป็นประโยชน์กับหัวข้อนี้และBrian Hurtพูดถึงวิธีแก้ปัญหาของliftการกระทำ monadic ใน monadic ที่คุณกำหนดเอง George Wilsonแสดงวิธีใช้mtlในการเขียนโค้ดที่ทำงานกับ monad ใด ๆ ที่ใช้ typeclasses ที่ต้องการแทนที่จะเป็น monad แบบกำหนดเองของคุณ Carlo Hamalainenเขียนบันทึกย่อสั้น ๆ ที่เป็นประโยชน์สรุปการพูดคุยของจอร์จ
liminalisht

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

ดังที่ @PaulJohnson ได้ชี้ให้เห็นแล้ววิธีการ Monad Transformer Stack นี้ดูเหมือนจะขัดแย้งกับรูปแบบการออกแบบ ReaderT
McBear Holden

43

การออกแบบโปรแกรมขนาดใหญ่ใน Haskell นั้นไม่แตกต่างจากการทำในภาษาอื่น การเขียนโปรแกรมในวงกว้างนั้นเกี่ยวกับการแบ่งปัญหาของคุณออกเป็นส่วนที่สามารถจัดการได้ ภาษาที่ใช้งานมีความสำคัญน้อยกว่า

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

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


14
ฉันพบจริงว่า refactoring ค่อนข้างน่าผิดหวังหากจำเป็นต้องเปลี่ยนชนิดข้อมูล มันต้องมีการดัดแปลง arity ของ constructors และการจับคู่รูปแบบอย่างน่าเบื่อ (ผมยอมรับว่าฟังก์ชั่น refactoring บริสุทธิ์เข้าไปในฟังก์ชั่นอื่น ๆ ของบริสุทธิ์ชนิดเดียวกันเป็นเรื่องง่าย - ตราบใดที่หนึ่งไม่ได้สัมผัสชนิดข้อมูล)
แดน

2
@Dan คุณสามารถออกไปได้อย่างสมบูรณ์ฟรีโดยมีการเปลี่ยนแปลงเล็กน้อย (เช่นการเพิ่มฟิลด์) เมื่อคุณใช้บันทึก บางคนอาจต้องการบันทึกนิสัย (ฉันเป็นหนึ่งในพวกเขา ^^ ")
MasterMastic

5
@Dan ฉันหมายความว่าถ้าคุณเปลี่ยนประเภทข้อมูลของฟังก์ชั่นในภาษาใด ๆ ที่คุณไม่ต้องทำเช่นเดียวกัน? ฉันไม่เห็นว่าภาษาเช่น Java หรือ C ++ จะช่วยคุณในเรื่องนี้อย่างไร หากคุณบอกว่าคุณสามารถใช้อินเทอร์เฟซทั่วไปบางอย่างที่ทั้งสองประเภทเชื่อฟังคุณควรทำสิ่งนั้นกับ Typeclasses ใน Haskell
อัฒภาค

4
@semicon ความแตกต่างสำหรับภาษาอย่าง Java คือการมีเครื่องมือที่พัฒนาแล้วที่ผ่านการทดสอบเป็นอย่างดีและมีระบบอัตโนมัติสำหรับการปรับโครงสร้างใหม่ โดยทั่วไปเครื่องมือเหล่านี้มีการรวมโปรแกรมแก้ไขที่ยอดเยี่ยมและนำงานน่าเบื่อจำนวนมากที่เกี่ยวข้องกับการปรับโครงสร้างใหม่ Haskell ให้ระบบที่ยอดเยี่ยมกับเราในการตรวจสอบสิ่งต่าง ๆ ที่จะต้องเปลี่ยนในการเปลี่ยนโครงสร้าง แต่เครื่องมือที่ใช้ในการดำเนินการจริงนั้นมี จำกัด มากโดยเฉพาะเมื่อเทียบกับสิ่งที่มีอยู่ใน Java ระบบนิเวศมานานกว่า 10 ปี
jsk

16

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

งานฝีมือของการเขียนโปรแกรมฟังก์ชั่น

งานฝีมือของการเขียนโปรแกรมฟังก์ชั่น

http://www.cs.kent.ac.uk/people/staff/sjt/craft2e/


11
ยิ่งไปกว่า Craft of FP คือ - ฉันได้เรียนรู้ Haskell จากมัน - มันเป็นข้อความเบื้องต้นสำหรับโปรแกรมเมอร์มือใหม่ไม่ใช่เพื่อการออกแบบระบบขนาดใหญ่ใน Haskell
Don Stewart

3
มันเป็นหนังสือที่ดีที่สุดที่ฉันรู้เกี่ยวกับการออกแบบ API และซ่อนรายละเอียดการใช้งาน ด้วยหนังสือเล่มนี้ฉันกลายเป็นโปรแกรมเมอร์ที่ดีขึ้นใน C ++ - เพียงเพราะฉันเรียนรู้วิธีที่ดีกว่าในการจัดระเบียบโค้ดของฉัน ประสบการณ์ของคุณ (และคำตอบ) ย่อมดีกว่าหนังสือเล่มนี้ แต่แดนอาจยังเป็นมือใหม่ใน Haskell ( where beginner=do write $ tutorials `about` Monads)
comonad

11

ฉันกำลังเขียนหนังสือชื่อ "การออกแบบเชิงหน้าที่และสถาปัตยกรรม" มันให้เทคนิคครบชุดแก่คุณในการสร้างแอปพลิเคชั่นขนาดใหญ่โดยใช้วิธีการทำงานที่บริสุทธิ์ มันอธิบายรูปแบบการทำงานและความคิดมากมายในขณะที่สร้างแอพพลิเคชั่นที่คล้ายกับ SCADA 'Andromeda' เพื่อควบคุมยานอวกาศตั้งแต่เริ่มต้น ภาษาหลักของฉันคือ Haskell หนังสือเล่มนี้ครอบคลุม:

  • แนวทางการสร้างแบบจำลองสถาปัตยกรรมโดยใช้ไดอะแกรม
  • การวิเคราะห์ความต้องการ
  • การสร้างแบบจำลองโดเมน DSL ในตัว
  • การออกแบบและติดตั้ง DSL ภายนอก
  • Monads เป็นระบบย่อยที่มีเอฟเฟกต์;
  • ฟรี monads เป็นส่วนต่อประสานการทำงาน;
  • eDSL ที่มีลูกศร
  • การผกผันของการควบคุมโดยใช้ eDSLs แบบ monadic ฟรี
  • ซอฟต์แวร์หน่วยความจำธุรกรรม
  • เลนส์;
  • รัฐ, Reader, Writer, RWS, ST monads;
  • สถานะไม่บริสุทธิ์: IORef, MVar, STM;
  • การสร้างโมเดลโดเมนแบบมัลติเธรดและแบบพร้อมกัน
  • GUI;
  • การบังคับใช้เทคนิคและวิธีการกระแสหลักเช่น UML, SOLID, GRASP;
  • การโต้ตอบกับระบบย่อยที่ไม่บริสุทธิ์

คุณอาจคุ้นเคยกับรหัสสำหรับหนังสือที่นี่และรหัสโครงการ'Andromeda'

ผมคาดว่าจะเสร็จสิ้นในหนังสือเล่มนี้ในตอนท้ายของ 2017 จนถึงที่เกิดขึ้นคุณอาจจะอ่านบทความของฉัน "การออกแบบและสถาปัตยกรรมในหน้าที่ Programming" (มาตุภูมิ) ที่นี่

UPDATE

ฉันแบ่งปันหนังสือของฉันทางออนไลน์ (5 บทแรก) ดูโพสต์บน Reddit


อเล็กซานเดอร์คุณช่วยกรุณาอัปเดตบันทึกย่อนี้เมื่อหนังสือของคุณเสร็จสมบูรณ์ดังนั้นเราจึงสามารถติดตามได้ ไชโย
Max

4
แน่นอน! สำหรับตอนนี้ฉันเสร็จครึ่งหนึ่งของข้อความ แต่มันเป็น 1/3 ของงานโดยรวม ดังนั้นให้ความสนใจของคุณเป็นแรงบันดาลใจให้ฉันมาก!
graninas

2
Hi! ฉันแชร์หนังสือของฉันออนไลน์ (เฉพาะ 5 บทแรกเท่านั้น) ดูโพสต์ใน Reddit: reddit.com/r/haskell/comments/6ck72h/ …
graninas

ขอบคุณสำหรับการแบ่งปันและทำงาน!
Max

รอคอยสิ่งนี้จริงๆ!
รักชาติ

7

โพสต์บล็อกของ Gabriel สถาปัตยกรรมโปรแกรมที่ปรับขนาดได้อาจจะคุ้มค่าพูดถึง

รูปแบบการออกแบบของ Haskell นั้นแตกต่างจากรูปแบบการออกแบบที่สำคัญในวิธีสำคัญอย่างหนึ่ง:

  • สถาปัตยกรรมทั่วไป : รวมองค์ประกอบหลายอย่างเข้าด้วยกันเป็นประเภท A เพื่อสร้าง "เครือข่าย" หรือ "โทโพโลยี" ของประเภท B

  • สถาปัตยกรรม Haskell : รวมองค์ประกอบหลาย ๆ อย่างเข้าด้วยกันเป็นประเภท A เพื่อสร้างส่วนประกอบใหม่ที่มีประเภทเดียวกันซึ่งแยกไม่ออกในตัวละครจากส่วนย่อยของมัน

บ่อยครั้งที่มันทำให้ฉันรู้สึกว่าสถาปัตยกรรมที่สง่างามมักจะหลุดพ้นจากห้องสมุดที่แสดงให้เห็นถึงความเป็นเนื้อเดียวกันในแบบล่างขึ้นบน ใน Haskell นี้ก็เห็นได้ชัดโดยเฉพาะอย่างยิ่ง - รูปแบบที่จะเป็นประเพณีที่ได้รับการพิจารณา "บนลงล่างสถาปัตยกรรม" มีแนวโน้มที่จะได้รับการบันทึกในห้องสมุดเช่นMVC , Netwireและเมฆ Haskell กล่าวคือฉันหวังว่าคำตอบนี้จะไม่ถูกตีความว่าเป็นความพยายามที่จะแทนที่คนอื่น ๆ ในหัวข้อนี้เพียงว่าตัวเลือกโครงสร้างสามารถและควรจะถูกแยกออกไปในห้องสมุดโดยผู้เชี่ยวชาญโดเมน ในความคิดของฉันความยากลำบากในการสร้างระบบขนาดใหญ่กำลังประเมินห้องสมุดเหล่านี้ในเรื่อง "ความดี" ทางสถาปัตยกรรมเทียบกับความกังวลในทางปฏิบัติทั้งหมดของคุณ

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


3
ฉันจะพูดถึงการโพสต์อีกครั้งโดยกาเบรียลอนซาเลซในหมวดรูปแบบการออกแบบ อาร์กิวเมนต์พื้นฐานของเขาคือสิ่งที่เราใช้ในการเขียนโปรแกรมคิดว่าเป็น "สถาปัตยกรรมที่ดี" เป็น "สถาปัตยกรรมประกอบ" - การออกแบบโปรแกรมโดยใช้รายการที่รับประกันว่าจะเขียน ตั้งแต่กฎหมายหมวดหมู่รับประกันได้ว่าตัวตนและการเชื่อมโยงกันจะถูกเก็บไว้ภายใต้องค์ประกอบสถาปัตยกรรม compositional จะทำได้โดยใช้แนวคิดที่เรามีหมวดหมู่ - ฟังก์ชั่นเช่นบริสุทธิ์กระทำเอกท่อ ฯลฯ
liminalisht


3

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

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

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