ในการdata
ประกาศตัวสร้างประเภทคือสิ่งที่อยู่ทางซ้ายมือของเครื่องหมายเท่ากับ ตัวสร้างข้อมูลคือสิ่งที่อยู่ทางขวามือของเครื่องหมายเท่ากับ คุณใช้ตัวสร้างประเภทที่คาดว่าจะมีประเภทและคุณใช้ตัวสร้างข้อมูลที่คาดว่าจะมีค่า
ตัวสร้างข้อมูล
เพื่อให้ง่ายขึ้นเราสามารถเริ่มต้นด้วยตัวอย่างของประเภทที่แสดงถึงสี
data Colour = Red | Green | Blue
ที่นี่เรามีตัวสร้างข้อมูลสามตัว Colour
เป็นชนิดและเป็นตัวสร้างที่มีค่าของชนิดGreen
Colour
ในทำนองเดียวกันRed
และมีทั้งการก่อสร้างว่าค่าสร้างประเภทBlue
Colour
เราคงนึกภาพออกได้!
data Colour = RGB Int Int Int
เรายังคงมีเพียงประเภทColour
แต่RGB
ไม่ใช่ค่า - เป็นฟังก์ชันที่ใช้สาม Ints และส่งคืนค่า! RGB
มีประเภท
RGB :: Int -> Int -> Int -> Colour
RGB
เป็นตัวสร้างข้อมูลที่เป็นฟังก์ชันที่รับค่าบางค่าเป็นอาร์กิวเมนต์จากนั้นใช้ค่าเหล่านั้นเพื่อสร้างค่าใหม่ หากคุณได้ทำการเขียนโปรแกรมเชิงวัตถุใด ๆ คุณควรตระหนักถึงสิ่งนี้ ใน OOP ตัวสร้างยังรับค่าบางค่าเป็นอาร์กิวเมนต์และส่งคืนค่าใหม่!
ในกรณีนี้ถ้าเราใช้RGB
กับสามค่าเราจะได้ค่าสี!
Prelude> RGB 12 92 27
#0c5c1b
เราได้สร้างค่าของประเภทColour
โดยใช้ตัวสร้างข้อมูล ตัวสร้างข้อมูลทั้งมีค่าเช่นตัวแปรจะหรือต้องใช้ค่าอื่น ๆ เป็นอาร์กิวเมนต์และสร้างใหม่ค่า หากคุณเคยเขียนโปรแกรมมาก่อนแนวคิดนี้ไม่น่าจะแปลกสำหรับคุณมากนัก
ช่วงระยะหยุดพัก
หากคุณต้องการสร้างต้นไม้ไบนารีเพื่อเก็บString
s คุณสามารถจินตนาการว่าจะทำสิ่งต่างๆเช่น
data SBTree = Leaf String
| Branch String SBTree SBTree
สิ่งที่เราเห็นนี้คือประเภทSBTree
ที่มีตัวสร้างข้อมูลสองตัว กล่าวอีกนัยหนึ่งมีสองฟังก์ชัน (คือLeaf
และBranch
) ที่จะสร้างค่าของSBTree
ประเภท หากคุณไม่คุ้นเคยกับการทำงานของต้นไม้ไบนารีเพียงแค่เข้าไปที่นั่น คุณไม่จำเป็นต้องรู้ว่าต้นไม้ไบนารีทำงานอย่างไรเพียงแต่ว่าต้นนี้เก็บString
ไว้ในทางใดทางหนึ่ง
นอกจากนี้เรายังเห็นว่าตัวสร้างข้อมูลทั้งสองมีString
อาร์กิวเมนต์ - นี่คือ String ที่พวกเขาจะเก็บไว้ในแผนภูมิ
แต่! จะเป็นอย่างไรหากเราต้องการจัดเก็บBool
ด้วยเราจะต้องสร้างต้นไม้ไบนารีใหม่ อาจมีลักษณะดังนี้:
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
ประเภทตัวสร้าง
ทั้งสองSBTree
และBBTree
เป็นตัวสร้างประเภท แต่มีปัญหาที่ชัดเจน คุณเห็นไหมว่ามันคล้ายกันแค่ไหน? นั่นเป็นสัญญาณว่าคุณต้องการพารามิเตอร์ที่ไหนสักแห่ง
ดังนั้นเราสามารถทำได้:
data BTree a = Leaf a
| Branch a (BTree a) (BTree a)
ตอนนี้เราแนะนำตัวแปร type a
เป็นพารามิเตอร์ให้กับ type constructor ในคำประกาศนี้BTree
ได้กลายเป็นฟังก์ชัน มันต้องใช้เวลาประเภทเป็นอาร์กิวเมนต์และมันส่งกลับใหม่ประเภท
มันเป็นสิ่งสำคัญที่นี่เพื่อพิจารณาความแตกต่างระหว่างที่ประเภทคอนกรีต (ตัวอย่าง ได้แก่Int
, [Char]
และMaybe Bool
) ซึ่งเป็นชนิดที่สามารถกำหนดให้มีค่าในโปรแกรมของคุณและฟังก์ชั่นประเภทคอนสตรัคที่คุณจำเป็นต้องให้อาหารชนิดเพื่อให้สามารถที่จะ กำหนดให้กับค่า ค่าไม่สามารถเป็นประเภท "list" ได้เนื่องจากต้องเป็น "list of something " ในจิตวิญญาณเดียวกันค่าไม่สามารถเป็นประเภท "ต้นไม้ไบนารี" ได้เพราะจำเป็นต้องเป็น "ต้นไม้ไบนารีที่เก็บบางสิ่ง "
ถ้าเราส่งผ่านกล่าวว่าBool
เป็นอาร์กิวเมนต์BTree
มันจะส่งกลับประเภทBTree Bool
ซึ่งเป็นต้นไม้ไบนารีที่เก็บBool
s แทนที่ตัวแปร type ทุกครั้งa
ด้วย type Bool
แล้วคุณจะเห็นเองว่ามันจริงแค่ไหน
หากคุณต้องการคุณสามารถดูBTree
เป็นฟังก์ชันด้วยชนิด
BTree :: * -> *
ชนิดค่อนข้างเหมือนประเภท - *
หมายถึงประเภทคอนกรีตดังนั้นเราจึงกล่าวว่าBTree
มาจากประเภทคอนกรีตไปจนถึงประเภทคอนกรีต
ห่อ
ย้อนกลับมาที่นี่สักครู่และสังเกตความคล้ายคลึงกัน
ตัวสร้างข้อมูลที่มีพารามิเตอร์นั้นยอดเยี่ยมหากเราต้องการให้ค่าของเราเปลี่ยนแปลงเล็กน้อย - เราใส่ความแปรผันเหล่านั้นในพารามิเตอร์และปล่อยให้คนที่สร้างค่าเป็นผู้ตัดสินใจว่าพวกเขาจะใส่อาร์กิวเมนต์ใดในแง่เดียวกันการพิมพ์ตัวสร้างที่มีพารามิเตอร์ก็เจ๋ง หากเราต้องการความแตกต่างเล็กน้อยในประเภทของเรา! เราใส่รูปแบบเหล่านั้นเป็นพารามิเตอร์และปล่อยให้คนที่สร้างประเภทตัดสินใจว่าพวกเขาจะใส่อาร์กิวเมนต์อะไร
กรณีศึกษา
ในฐานะที่เป็นบ้านที่นี่เราสามารถพิจารณาMaybe a
ประเภทได้ คำจำกัดความของมันคือ
data Maybe a = Nothing
| Just a
นี่Maybe
คือตัวสร้างชนิดที่ส่งคืนประเภทคอนกรีต Just
เป็นตัวสร้างข้อมูลที่ส่งคืนค่า Nothing
เป็นตัวสร้างข้อมูลที่มีค่า ถ้าเราดูประเภทของJust
เราจะเห็นว่า
Just :: a -> Maybe a
ในคำอื่น ๆJust
ใช้ค่าของชนิดและผลตอบแทนค่าของชนิดa
Maybe a
ถ้าเราดูประเภทของMaybe
เราจะเห็นว่า
Maybe :: * -> *
กล่าวอีกนัยหนึ่งคือMaybe
รับประเภทคอนกรีตและส่งคืนประเภทคอนกรีต
อีกครั้ง! ความแตกต่างระหว่างประเภทคอนกรีตและฟังก์ชันตัวสร้างประเภท คุณไม่สามารถสร้างรายการMaybe
s ได้หากคุณพยายามดำเนินการ
[] :: [Maybe]
คุณจะได้รับข้อผิดพลาด แต่คุณสามารถสร้างรายการหรือMaybe Int
Maybe a
นั่นเป็นเพราะMaybe
เป็นฟังก์ชันตัวสร้างชนิด แต่รายการต้องมีค่าของประเภทคอนกรีต Maybe Int
และMaybe a
เป็นประเภทคอนกรีต (หรือถ้าคุณต้องการให้เรียกใช้ฟังก์ชันตัวสร้างที่ส่งคืนชนิดคอนกรีต)
Car
เป็นทั้งตัวสร้างประเภท (ทางด้านซ้ายของ=
) และตัวสร้างข้อมูล (ทางด้านขวา) ในตัวอย่างแรกตัวCar
สร้างประเภทจะไม่มีอาร์กิวเมนต์ในตัวอย่างที่สองจะใช้เวลาสาม ในทั้งสองตัวอย่างตัวCar
สร้างข้อมูลรับอาร์กิวเมนต์สามตัว (แต่ประเภทของอาร์กิวเมนต์เหล่านั้นอยู่ในกรณีเดียวคงที่และในพารามิเตอร์อื่น ๆ )