จริงๆแล้วมันเป็นเพียงตัวสร้างข้อมูลธรรมดาที่ถูกกำหนดไว้ในPreludeซึ่งเป็นไลบรารีมาตรฐานที่นำเข้าโดยอัตโนมัติในทุกโมดูล
สิ่งที่อาจจะเป็นโครงสร้าง
คำจำกัดความมีลักษณะดังนี้:
data Maybe a = Just a
| Nothing
ประกาศที่กำหนดประเภท, Maybe a
ซึ่งจะแปรตามตัวแปรประเภทซึ่งหมายความเพียงแค่ว่าคุณสามารถใช้มันด้วยวิธีใดในสถานที่ของa
a
การสร้างและการทำลายล้าง
ประเภทนี้มีตัวสร้างสองตัวJust a
และNothing
. เมื่อประเภทมีตัวสร้างหลายตัวหมายความว่าค่าของประเภทจะต้องถูกสร้างขึ้นด้วยตัวสร้างที่เป็นไปได้เพียงตัวเดียว สำหรับประเภทนี้ค่าถูกสร้างขึ้นโดยผ่านJust
หรือNothing
ไม่มีความเป็นไปได้อื่น ๆ (ไม่ใช่ข้อผิดพลาด)
เนื่องจากNothing
ไม่มีพารามิเตอร์ชนิดเมื่อใช้เป็นตัวสร้างชื่อมันมีค่าคงที่เป็นสมาชิกประเภททุกประเภทMaybe a
a
แต่ตัวJust
สร้างมีพารามิเตอร์ชนิดซึ่งหมายความว่าเมื่อใช้เป็นตัวสร้างมันจะทำหน้าที่เหมือนฟังก์ชันจากชนิดa
ถึงMaybe a
กล่าวคือมีประเภทa -> Maybe a
ดังนั้นตัวสร้างประเภทจึงสร้างมูลค่าของประเภทนั้น อีกด้านหนึ่งคือเมื่อคุณต้องการใช้ค่านั้นและนั่นคือจุดที่การจับคู่รูปแบบเข้ามาเล่น ซึ่งแตกต่างจากฟังก์ชันตัวสร้างสามารถใช้ในนิพจน์การผูกรูปแบบและนี่คือวิธีที่คุณสามารถวิเคราะห์กรณีของค่าที่เป็นของชนิดที่มีตัวสร้างมากกว่าหนึ่งตัว
ในการใช้Maybe a
ค่าในการจับคู่รูปแบบคุณต้องระบุรูปแบบสำหรับตัวสร้างแต่ละตัวดังนี้:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
ในการแสดงออกที่กรณีที่รูปแบบครั้งแรกจะตรงกับถ้าค่าเป็นและที่สองจะตรงกับถ้าค่าที่ถูกสร้างขึ้นด้วยNothing
Just
หากอันที่สองตรงกันชื่อนี้จะผูกชื่อval
กับพารามิเตอร์ที่ส่งผ่านไปยังตัวJust
สร้างเมื่อสร้างค่าที่คุณจับคู่ด้วย
สิ่งที่อาจหมายถึง
บางทีคุณอาจคุ้นเคยกับวิธีการทำงานนี้แล้ว ไม่มีความมหัศจรรย์ใด ๆ ต่อMaybe
ค่ามันเป็นเพียงประเภทข้อมูลพีชคณิตของ Haskell ปกติ (ADT) แต่มีการใช้ค่อนข้างน้อยเนื่องจาก "ยก" หรือขยายประเภทได้อย่างมีประสิทธิภาพเช่นInteger
จากตัวอย่างของคุณไปสู่บริบทใหม่ที่มีค่าพิเศษ ( Nothing
) ซึ่งแสดงถึงการขาดคุณค่า! ระบบประเภทแล้วคุณจะต้องตรวจสอบว่าค่าพิเศษก่อนที่มันจะช่วยให้คุณได้รับที่Integer
ว่าอาจจะมี วิธีนี้ป้องกันข้อบกพร่องจำนวนมาก
หลายภาษาในปัจจุบันจัดการค่า "ไม่มีค่า" ประเภทนี้ผ่านการอ้างอิง NULL Tony Hoare นักวิทยาศาสตร์คอมพิวเตอร์ที่มีชื่อเสียง (เขาเป็นผู้คิดค้น Quicksort และเป็นผู้ชนะรางวัล Turing Award) เป็นเจ้าของสิ่งนี้ในฐานะ"ความผิดพลาดพันล้านดอลลาร์" ของเขา ประเภทบางทีไม่ใช่วิธีเดียวในการแก้ไขปัญหานี้ แต่ได้รับการพิสูจน์แล้วว่าเป็นวิธีที่มีประสิทธิภาพ
อาจจะเป็น Functor
ความคิดของการเปลี่ยนประเภทหนึ่งไปยังอีกที่หนึ่งเช่นว่าการดำเนินการกับชนิดเก่าสามารถยังถูกเปลี่ยนการทำงานในรูปแบบใหม่เป็นแนวคิดที่อยู่เบื้องหลังระดับประเภท Haskell เรียกว่าFunctor
ซึ่งMaybe a
มีตัวอย่างการใช้งานของ
Functor
จัดเตรียมวิธีการที่เรียกว่าfmap
ซึ่งแมปฟังก์ชันที่มีช่วงค่าจากประเภทพื้นฐาน (เช่นInteger
) ไปยังฟังก์ชันที่มีช่วงค่าจากประเภทที่ยกขึ้น (เช่นMaybe Integer
) ฟังก์ชันที่แปลงfmap
เพื่อทำงานกับMaybe
ค่าจะทำงานดังนี้:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
ดังนั้นหากคุณมีMaybe Integer
ค่าm_x
และInt -> Int
ฟังก์ชันf
คุณสามารถfmap f m_x
นำฟังก์ชันไปใช้ได้f
โดยตรงMaybe Integer
โดยไม่ต้องกังวลว่าจะมีค่าจริงหรือไม่ ในความเป็นจริงคุณสามารถใช้ห่วงโซ่ของInteger -> Integer
ฟังก์ชันยกทั้งหมดกับMaybe Integer
ค่าและต้องกังวลเกี่ยวกับการตรวจสอบอย่างชัดเจนNothing
เพียงครั้งเดียวเมื่อคุณทำเสร็จแล้ว
อาจจะเป็น Monad
ผมไม่แน่ใจว่าคุณจะคุ้นเคยกับแนวคิดของการที่Monad
แต่คุณมีอย่างน้อยใช้IO a
ก่อนและประเภทลายเซ็นรูปลักษณ์ที่น่าทึ่งคล้ายกับIO a
Maybe a
แม้ว่าจะIO
มีความพิเศษตรงที่จะไม่เปิดเผยตัวสร้างให้คุณและสามารถ "รัน" ได้โดยระบบรันไทม์ของ Haskell เท่านั้น แต่ก็ยังเป็นFunctor
ไฟล์Monad
. ในความเป็นจริงมีความรู้สึกที่สำคัญซึ่ง a Monad
เป็นเพียงลักษณะพิเศษที่Functor
มีคุณสมบัติพิเศษบางอย่าง แต่นี่ไม่ใช่สถานที่ที่จะเข้าไปในนั้น
อย่างไรก็ตาม Monads ชอบIO
ประเภทแผนที่เป็นประเภทใหม่ที่แสดงถึง "การคำนวณที่ทำให้เกิดค่า" และคุณสามารถยกฟังก์ชันออกเป็นMonad
ประเภทได้ผ่านfmap
ฟังก์ชันที่เหมือนมากซึ่งเรียก liftM
ว่าฟังก์ชันปกติให้เป็น "การคำนวณที่ให้ผลลัพธ์เป็นค่าที่ได้จากการประเมินค่า ฟังก์ชั่น."
คุณอาจเดาได้ (ถ้าคุณอ่านมาจนถึงตอนนี้) นั่นMaybe
ก็คือไฟล์Monad
. ซึ่งแสดงถึง "การคำนวณที่ไม่สามารถคืนค่าได้" เช่นเดียวกับfmap
ตัวอย่างนี้ช่วยให้คุณสามารถคำนวณได้ทั้งหมดโดยไม่ต้องตรวจสอบข้อผิดพลาดอย่างชัดเจนหลังจากแต่ละขั้นตอน และในความเป็นจริงวิธีการสร้างMonad
อินสแตนซ์การคำนวณเกี่ยวกับMaybe
ค่าจะหยุดลงทันทีที่Nothing
พบa ดังนั้นจึงเหมือนกับการยกเลิกทันทีหรือผลตอบแทนที่ไร้ค่าในระหว่างการคำนวณ
คุณอาจจะเขียนได้
อย่างที่ฉันได้กล่าวไปก่อนหน้านี้ไม่มีอะไรที่อยู่ในMaybe
ประเภทที่รวมเข้ากับไวยากรณ์ของภาษาหรือระบบรันไทม์ หาก Haskell ไม่ได้จัดเตรียมไว้เป็นค่าเริ่มต้นคุณสามารถใช้ฟังก์ชันทั้งหมดได้ด้วยตัวคุณเอง! ในความเป็นจริงคุณสามารถเขียนซ้ำได้ด้วยตัวเองโดยใช้ชื่อที่แตกต่างกันและได้รับฟังก์ชันการทำงานเหมือนกัน
หวังว่าคุณจะเข้าใจMaybe
ประเภทและตัวสร้างในตอนนี้ แต่หากยังมีอะไรไม่ชัดเจนโปรดแจ้งให้เราทราบ!
Maybe
ที่ที่ภาษาอื่น ๆ จะใช้null
หรือnil
(มีสิ่งที่น่ารังเกียจNullPointerException
แฝงตัวอยู่ทุกมุม) ตอนนี้ภาษาอื่น ๆ ก็เริ่มใช้โครงสร้างนี้เช่นกัน: Scala asOption
และแม้แต่ Java 8 ก็มีOptional
ประเภท