ไม่มีข้อ จำกัด เลย! เมื่อฉันเริ่มเรียนรู้พื้นฐานหมวดหมู่ - ทฤษฎีสำหรับตัวสร้างแบบพิมพ์จุดนี้ทำให้ฉันสับสนเช่นกัน เราจะไปที่ แต่ก่อนอื่นให้ฉันกำจัดความสับสน คำพูดสองคำนี้:
functor ดังกล่าวสามารถมีได้ตามหมวดหมู่เป้าหมายหมวดหมู่ที่สร้างขึ้นโดยใช้ตัวสร้างประเภท
และ
อาจคิดว่า functors มีหมวดหมู่ใด ๆ ที่เป็นเป้าหมายของ functor เช่นหมวดหมู่ของ Haskell ทุกประเภท
แสดงให้เห็นว่าคุณเข้าใจผิดว่า functor คืออะไร (หรืออย่างน้อยที่สุดคุณกำลังใช้คำศัพท์ในทางที่ผิด)
Functors ไม่สร้างหมวดหมู่ functor เป็นการทำแผนที่ระหว่างหมวดหมู่ Functors นำวัตถุและมอร์ฟิซึ่มส์ (ประเภทและฟังก์ชั่น) ในหมวดหมู่ของแหล่งที่มาเพื่อวัตถุและมอร์ฟิซึ่มส์ในหมวดหมู่เป้าหมาย
โปรดทราบว่านี้หมายถึง functor เป็นจริงคู่ของแมปการทำแผนที่บนวัตถุF_objและการทำแผนที่ใน morphisms F_morph ใน Haskell, ส่วนวัตถุF_objของ functor เป็นชื่อของตัวสร้างประเภท (เช่นList
) ในขณะที่ส่วนหนึ่งซึ่มส์เป็นฟังก์ชั่นfmap
(มันขึ้นอยู่กับคอมไพเลอร์ Haskell จะสังคายนาซึ่งfmap
เราหมายถึงการแสดงออกใดก็ตาม) ดังนั้นเราไม่สามารถพูดได้ว่าList
เป็นนักแสดง เพียงการรวมกันของList
และfmap
เป็นนักแสดง แต่ถึงกระนั้นการใช้คำพูดในทางที่ผิด โปรแกรมเมอร์เรียกList
functor ในขณะที่หมวดหมู่ทฤษฎีใช้สัญลักษณ์เดียวกันเพื่ออ้างถึงทั้งสองส่วนของ functor
นอกจากนี้ในการเขียนโปรแกรมฟังก์ชั่นเกือบทั้งหมดเป็นendofunctorsนั่นคือหมวดที่มาและเป้าหมายเหมือนกัน - หมวดหมู่ทุกประเภทในภาษาของเรา ขอเรียกนี้หมวดหมู่ประเภท endofunctor Fในประเภทแผนที่ชนิดTประเภทอื่นFTและฟังก์ชั่นT -> Sฟังก์ชั่นอื่นFT -> FS แน่นอนว่าการทำแผนที่นี้ต้องเป็นไปตามกฎหมายนักแสดง
ใช้List
เป็นตัวอย่าง: เรามีตัวสร้างประเภทList : Type -> Type
และฟังก์ชั่นfmap: (a -> b) -> (List a -> List b)
ที่รวมกันเป็น functor T
มีจุดสุดท้ายที่ชัดเจนขึ้น การเขียนList int
ไม่ได้สร้างรายการจำนวนเต็มชนิดใหม่ ประเภทนี้อยู่แล้ว มันเป็นวัตถุที่อยู่ในหมวดหมู่ของเราประเภท List Int
เป็นเพียงวิธีในการอ้างถึง
ตอนนี้คุณกำลังสงสัยว่าทำไม functor ไม่สามารถ map ประเภทไปพูดหรือInt
String
แต่มันสามารถ! เพียงแค่มีการใช้ functor ตัวตน สำหรับหมวดหมู่Cนักแสดงตัวตนจะจับคู่วัตถุทุกอย่างเข้ากับตัวเองและมอร์ฟิซึ่มส์กับตัวเอง มันเป็นเรื่องง่ายที่จะตรวจสอบการทำแผนที่นี้เป็นไปตามกฎหมายของนักแสดง ใน Haskell นี่จะเป็นตัวสร้างประเภทid : * -> *
ที่แมปทุกประเภทกับตัวมันเอง ยกตัวอย่างเช่นการประเมินid int
int
ยิ่งไปกว่านั้นเราสามารถสร้างฟังก์ชั่นคงที่ซึ่งแมปทุกประเภทเป็นประเภทเดียว ตัวอย่างเช่น functor ToInt : * -> *
ที่ToInt a = int
ทุกประเภทa
และแมป morphisms ทั้งหมดกับฟังก์ชันจำนวนเต็ม: fmap f = \x -> x