ทำไมฉันถึงต้องใส่ใจ Haskell? Monad คืออะไรและทำไมฉันต้องใช้ [ปิด]


9

ฉันไม่ได้รับสิ่งที่พวกเขาแก้ปัญหา


1
เกือบจะเหมือนกันกับ: programmers.stackexchange.com/questions/25569/…
Orbling

2
ฉันคิดว่าการแก้ไขนี้ค่อนข้างรุนแรง ฉันคิดว่าคำถามของคุณเป็นคำถามที่ดี มันเป็นเพียงบางส่วนของมันที่ค่อนข้าง ... ซึ่งอาจเป็นเพียงผลมาจากความยุ่งยากในการพยายามเรียนรู้สิ่งที่คุณไม่เห็นจุด
Jason Baker

@SnOrfus ฉันเป็นคนที่เสแสร้งคำถาม ฉันขี้เกียจเกินไปที่จะแก้ไขอย่างถูกต้อง
งาน

คำตอบ:


34

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

Monad คืออะไร วิธีที่ดีที่สุดในการคิดถึง Monad คือรูปแบบการออกแบบ ในกรณีของ I / O คุณอาจจะคิดว่ามันเป็นมากกว่าท่อส่งเกียรติที่รัฐโลกเป็นสิ่งที่ได้รับผ่านระหว่างขั้นตอน

ตัวอย่างเช่นลองโค้ดที่คุณเขียน:

do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Nice to meet you, " ++ name ++ "!")

มีอะไรอีกมากมายเกิดขึ้นที่นี่มากกว่าสบตา ตัวอย่างเช่นคุณจะสังเกตเห็นว่ามีลายเซ็นต่อไปนี้:putStrLn putStrLn :: String -> IO ()ทำไมนี้

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

global_state <- (\(stdin, stdout) -> (stdin, stdout ++ "What is your name?")) global_state

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

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

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


6
ย่อหน้าสุดท้ายคือทองคำ ในการแยกและถอดความมันบิต: "ภาษาที่จำเป็นคือภาษาที่อนุญาตให้มีผลข้างเคียงโดยค่าเริ่มต้น แต่ช่วยให้คุณสามารถเขียนรหัสการทำงานได้ถ้าคุณต้องการจริงๆภาษาการทำงานนั้นใช้งานได้อย่างหมดจดโดยค่าเริ่มต้น ถ้าคุณต้องการจริงๆ "
Frank Shearar

เป็นเรื่องน่าสังเกตว่ากระดาษที่คุณเชื่อมโยงไปนั้นปฏิเสธความคิดที่ว่า "การเปลี่ยนแปลงไม่ได้ในฐานะที่เป็นประโยชน์ของการเขียนโปรแกรมฟังก์ชั่น" โดยเฉพาะในตอนแรก
Mason Wheeler

@MasonWheeler: ผมอ่านวรรคเหล่านั้นไม่เป็นความสำคัญของการไล่เปลี่ยนไม่ได้ แต่ปฏิเสธว่ามันเป็นข้อโต้แย้งที่น่าเชื่อสำหรับการแสดงให้เห็นถึงความเหนือกว่าโปรแกรมการทำงานของ ในความเป็นจริงเขาพูดในสิ่งเดียวกันเกี่ยวกับการกำจัดgoto(เป็นข้อโต้แย้งสำหรับการเขียนโปรแกรมเชิงโครงสร้าง) เล็กน้อยในภายหลังในกระดาษลักษณะลักษณะข้อโต้แย้งเช่น "ไร้ผล" และยังไม่มีพวกเราคนใดที่ปรารถนาจะgotoกลับมาอย่างลับๆ เป็นเพียงการที่คุณไม่สามารถโต้แย้งได้ว่าgotoไม่จำเป็นสำหรับผู้ที่ใช้มันอย่างกว้างขวาง
Robert Harvey

7

ฉันจะกัด !!! Monads ด้วยตัวเองไม่ได้เป็น raison d'etre สำหรับ Haskell (Haskell รุ่นแรก ๆ ไม่มีแม้แต่พวกเขา)

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

วิวัฒนาการของโปรแกรมเมอร์ Haskell เป็นเรื่องตลกมันไม่ได้ตั้งใจจะเอาจริงเอาจัง

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

คุณถามเกี่ยวกับ "อาจ / Identity / Safe Division monads ???" อาจจะเป็นตัวอย่างของวิธีที่คุณสามารถใช้การจัดการข้อยกเว้น (ง่ายมากเพียงข้อยกเว้นเดียว) ในการเป็นห้องสมุด

คุณพูดถูกการเขียนข้อความและการอ่านข้อมูลผู้ใช้นั้นไม่เหมือนใคร IO เป็นตัวอย่างที่น่ารังเกียจของ "monads as a feature"

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


ที่จริงแล้ว Haskell ให้การสนับสนุนตัวแปรที่ไม่แน่นอนผ่าน ST monad (หนึ่งในไม่กี่ส่วนที่ไม่น่าเชื่อของภาษาที่เล่นโดยกฎของตัวเอง)
sara

4

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

ฉันคิดว่าคนที่แตกต่างกันแค่คิดแตกต่างกันและถ้าคุณไม่ได้ถูกล่อลวงด้วยน้ำตาล syntactic หรือนามธรรมโดยเฉพาะอย่างยิ่งที่มีอยู่เพื่อความสะดวกสบายและมีค่าใช้จ่ายจริงที่สำคัญแล้วโดยทั้งหมดอยู่ห่างจากภาษาดังกล่าว

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

และเหนือสิ่งอื่นใดพยายามหลีกเลี่ยงการถูกแฟนบอยพูดโดยเฉพาะกับคนที่ไม่รู้จริง ๆ ว่าพวกเขากำลังพูดถึงอะไร


4

Haskell บังคับใช้Referential Transparency : กำหนดพารามิเตอร์เดียวกันทุกฟังก์ชั่นส่งคืนผลลัพธ์เดียวกันเสมอไม่ว่าคุณจะเรียกใช้ฟังก์ชันนั้นกี่ครั้งก็ตาม

นั่นหมายความว่าตัวอย่างเช่นใน Haskell (และไม่มี Monads) คุณไม่สามารถใช้เครื่องกำเนิดตัวเลขแบบสุ่มได้ ใน C ++ หรือ Java คุณสามารถทำได้โดยใช้ตัวแปรส่วนกลางเก็บค่า "seed" ระดับกลางของเครื่องกำเนิดแบบสุ่ม

บน Haskell ตัวแปรทั่วโลกเป็น Monads


ดังนั้น ... ถ้าคุณต้องการเครื่องกำเนิดตัวเลขแบบสุ่มล่ะ มันไม่ได้เป็นฟังก์ชั่นเช่นกัน? แม้ว่าจะไม่ฉันจะทำให้ตัวสร้างตัวเลขสุ่มได้ด้วยตนเองได้อย่างไร
งาน

@ งานคุณสามารถสร้างตัวสร้างตัวเลขสุ่มภายใน monad (โดยพื้นฐานแล้วมันคือ state-tracker) หรือคุณสามารถใช้ unsafePerformIO, ปีศาจแห่ง Haskell ที่ไม่ควรใช้ ด้านในของมัน!)
ทางเลือก

ใน Haskell คุณจะผ่าน 'RandGen' ซึ่งเป็นสถานะปัจจุบันของ RNG ดังนั้นฟังก์ชั่นที่สร้างหมายเลขสุ่มใหม่จะใช้ RandGen และส่งคืน tuple ด้วย RandGen ใหม่และหมายเลขที่สร้างขึ้น ทางเลือกคือการระบุตำแหน่งที่คุณต้องการรายการของตัวเลขสุ่มระหว่างนาทีและค่าสูงสุด นี่จะคืนค่าจำนวนอนันต์ที่ประเมินอย่างเกียจคร้านดังนั้นเราสามารถผ่านรายการนี้เมื่อใดก็ตามที่เราต้องการหมายเลขสุ่มใหม่
Qqwy

เช่นเดียวกับที่คุณได้รับในภาษาอื่น ๆ ! คุณได้รับอัลกอริธึมกำเนิดตัวเลขแบบสุ่มหลอกแล้วคุณก็หว่านมันด้วยค่าบางส่วนและเก็บเกี่ยวตัวเลข "สุ่ม" ที่โผล่ออกมา! ความแตกต่างเพียงอย่างเดียวคือภาษาเช่น C # และ Java จะทำการติดตั้ง PRNG ให้คุณโดยอัตโนมัติโดยใช้นาฬิกาของระบบหรือสิ่งต่างๆ และความจริงที่ว่าใน Haskell คุณจะได้รับ PRNG ใหม่ที่คุณสามารถใช้เพื่อรับหมายเลข "ถัดไป" ในขณะที่ใน C # / Java สิ่งนี้ทำภายในทั้งหมดโดยใช้ตัวแปรที่ไม่แน่นอนในRandomวัตถุ
sara

4

เป็นคำถามแบบเก่า แต่เป็นคำถามที่ดีจริงๆดังนั้นฉันจะตอบ

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

ฉันจะให้ตัวอย่างของสิ่งที่พระเปิดใช้งานซึ่งอาจเป็นเรื่องยาก ไม่มีตัวอย่างเหล่านี้อยู่ใน Haskell เพียงเพราะความรู้ของ Haskell ของฉันสั่นเล็กน้อย แต่พวกเขาทั้งหมดเป็นตัวอย่างของ Haskell ที่เป็นแรงบันดาลใจให้ใช้ monads

parsers

โดยปกติถ้าคุณต้องการเขียนโปรแกรมแยกวิเคราะห์บางส่วนเพื่อใช้ภาษาการเขียนโปรแกรมคุณจะต้องอ่านข้อกำหนดของ BNFและเขียนรหัส loopy ทั้งกลุ่มเพื่อแยกวิเคราะห์หรือคุณต้องใช้คอมไพเลอร์คอมไพเลอร์เช่น Flex, Bison, yacc เป็นต้น แต่ด้วย monads คุณสามารถสร้าง "compars parser" ใน Haskell ได้

โปรแกรมแยกวิเคราะห์ไม่สามารถทำได้โดยไม่ต้องใช้พระหรือภาษาวัตถุประสงค์พิเศษเช่น yacc, bison เป็นต้น

ตัวอย่างเช่นฉันใช้ข้อกำหนดภาษา BNF สำหรับโปรโตคอล IRC :

message    =  [ ":" prefix SPACE ] command [ params ] crlf
prefix     =  servername / ( nickname [ [ "!" user ] "@" host ] )
command    =  1*letter / 3digit
params     =  *14( SPACE middle ) [ SPACE ":" trailing ]
           =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]

nospcrlfcl =  %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF
                ; any octet except NUL, CR, LF, " " and ":"
middle     =  nospcrlfcl *( ":" / nospcrlfcl )
trailing   =  *( ":" / " " / nospcrlfcl )

SPACE      =  %x20        ; space character
crlf       =  %x0D %x0A   ; "carriage return" "linefeed"

และกระทืบมันลงไปประมาณ 40 บรรทัดของรหัสใน F # (ซึ่งเป็นภาษาอื่นที่รองรับพระ):

type UserIdentifier = { Name : string; User: string; Host: string }

type Message = { Prefix : UserIdentifier option; Command : string; Params : string list }

let space = character (char 0x20)

let parameters =
    let middle = parser {
        let! c = sat <| fun c -> c <> ':' && c <> (char 0x20)
        let! cs = many <| sat ((<>)(char 0x20))
        return (c::cs)
    }
    let trailing = many item
    let parameter = prefixed space ((prefixed (character ':') trailing) +++ middle)
    many parameter

let command = atLeastOne letter +++ (count 3 digit)

let prefix = parser {
    let! name = many <| sat (fun c -> c <> '!' && c <> '@' && c <> (char 0x20))   //this is more lenient than RFC2812 2.3.1
    let! uh = parser {
        let! user = maybe <| prefixed (character '!') (many <| sat (fun c -> c <> '@' && c <> (char 0x20)))
        let! host = maybe <| prefixed (character '@') (many <| sat ((<>) ' '))
        return (user, host)
    }
    let nullstr = function | Some([]) -> null | Some(s) -> charsString s | _ -> null
    return { Name = charsString name; User = nullstr (fst uh); Host = nullstr (snd uh) }
}

let message = parser {
    let! p = maybe (parser {
        let! _ = character ':'
        let! p = prefix
        let! _ = space
        return p
    })
    let! c = command
    let! ps = parameters
    return { Prefix = p; Command = charsString c; Params = List.map charsString ps }
}

ไวยากรณ์ของ monad ของ F # นั้นค่อนข้างน่าเกลียดเมื่อเทียบกับ Haskell และฉันน่าจะได้รับการปรับปรุงให้ดีขึ้นเล็กน้อย - แต่จุดที่จะกลับบ้านก็คือโครงสร้างรหัส parser นั้นเหมือนกับ BNF สิ่งนี้ไม่เพียง แต่จะทำงานได้มากขึ้นโดยไม่ต้อง monads (หรือตัวแยกวิเคราะห์) มันก็แทบจะไม่มีความคล้ายคลึงกับสเปคและมันก็แย่มากทั้งในการอ่านและการบำรุงรักษา

มัลติทาสกิ้งที่กำหนดเอง

โดยปกติแล้วมัลติทาสกิ้งคิดว่าเป็นคุณลักษณะของระบบปฏิบัติการ - แต่ด้วย monads คุณสามารถเขียนกำหนดการของคุณเองซึ่งหลังจากแต่ละคำสั่ง monad โปรแกรมจะผ่านการควบคุมไปยังตัวกำหนดตารางเวลาซึ่งจะเลือก monad อื่นเพื่อดำเนินการ

ผู้ชายคนหนึ่งทำ"งาน" monadเพื่อควบคุมลูปเกม (อีกครั้งใน F #) ดังนั้นแทนที่จะต้องเขียนทุกอย่างเป็นเครื่องรัฐที่ทำหน้าที่ในการUpdate()โทรแต่ละครั้งเขาก็สามารถเขียนคำแนะนำทั้งหมดราวกับว่าพวกเขาเป็นฟังก์ชั่นเดียว .

กล่าวอีกนัยหนึ่งแทนที่จะต้องทำสิ่งที่ชอบ:

class Robot
{
   enum State { Walking, Shooting, Stopped }

   State state = State.Stopped;

   public void Update()
   {
      switch(state)
      {
         case State.Stopped:
            Walk();
            state = State.Walking;
            break;
         case State.Walking:
            if (enemyInSight)
            {
               Shoot();
               state = State.Shooting;
            }
            break;
      }
   }
}

คุณสามารถทำสิ่งที่ชอบ:

let robotActions = task {
   while (not enemyInSight) do
      Walk()
   while (enemyInSight) do
      Shoot()
}

LINQ เป็น SQL

LINQ to SQL เป็นตัวอย่างของ monad และฟังก์ชันการทำงานที่คล้ายกันสามารถนำมาใช้ใน Haskell ได้อย่างง่ายดาย

ฉันจะไม่ได้ลงรายละเอียดตั้งแต่ผมจำไม่ได้ว่าทุกสิ่งที่ถูกต้อง แต่เอริคเมย์เยอร์อธิบายได้ค่อนข้างดี


1

หากคุณคุ้นเคยกับรูปแบบ GoF พระจะเปรียบเหมือนรูปแบบมัณฑนากรและรูปแบบตัวสร้างรวมกันบนสเตียรอยด์กัดโดยตัวรบกวนกัมมันตภาพรังสี

มีคำตอบที่ดีกว่าด้านบน แต่ประโยชน์บางอย่างที่ฉันเห็นคือ:

  • พระตกแต่งรูปแบบแกนกลางที่มีคุณสมบัติเพิ่มเติมโดยไม่ต้องเปลี่ยนประเภทแกน ตัวอย่างเช่น monad อาจ "ยก" สตริงและเพิ่มค่าเช่น "isWellFormed", "isProfanity" หรือ "isPalindrome" เป็นต้น

  • ในทำนองเดียวกัน monads อนุญาตให้กลุ่มที่เรียบง่ายเป็นประเภทคอลเลกชัน

  • Monads อนุญาตให้มีการผูกฟังก์ชั่นในพื้นที่ที่มีลำดับสูงกว่านี้ได้

  • monads อนุญาตให้ผสมฟังก์ชั่นโดยพลการและข้อโต้แย้งกับชนิดข้อมูลเองในพื้นที่ที่สูงขึ้น

  • Monads อนุญาตให้ผสมผสานฟังก์ชั่นบริสุทธิ์ไร้สัญชาติด้วยฐานที่ไม่บริสุทธิ์และไร้รัฐเพื่อให้คุณสามารถติดตามว่าปัญหาอยู่ที่ไหน

ตัวอย่างที่คุ้นเคยของ monad ใน Java คือ List ใช้คลาสหลักบางอย่างเช่นสตริงและ "ยก" ลงในพื้นที่ monad ของ List เพิ่มข้อมูลเกี่ยวกับรายการ จากนั้นจะผูกฟังก์ชันใหม่ลงในพื้นที่นั้นเช่น get (), getFirst (), add (), empty () ฯลฯ

ในขนาดใหญ่ลองจินตนาการว่าแทนที่จะเขียนโปรแกรมคุณเพียงแค่เขียน Builder ขนาดใหญ่ (เป็นรูปแบบ GoF) และวิธีการ build () ในท้ายที่สุดจะถกเถียงกันว่าอะไรก็ตามที่โปรแกรมควรจะสร้าง และคุณสามารถเพิ่มวิธีการใหม่ใน ProgramBuilder ของคุณโดยไม่ต้องคอมไพล์โค้ดต้นฉบับใหม่ นั่นเป็นเหตุผลว่าทำไม monads จึงเป็นรูปแบบการออกแบบที่ทรงพลัง

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