คำศัพท์ที่ถูกต้องในทฤษฎีประเภท: ประเภทประเภทก่อสร้างประเภท / ประเภทและค่า


14

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

ข้อตกลงที่น่าสงสัยและความสัมพันธ์ของพวกเขาคือชนิดประเภทคอนสตรัคชนิดพารามิเตอร์ชนิดหรือประเภทและค่านิยม

ฉันได้ตรวจสอบวิกิพีเดียเพื่อศึกษาทฤษฎีการพิมพ์ด้วย แต่ก็ไม่ได้อธิบายอย่างชัดเจนเช่นกัน

ดังนั้นเพื่อให้มีคำตอบอ้างอิงที่ดีและตรวจสอบความเข้าใจของฉัน:

  • สิ่งเหล่านี้ถูกกำหนดไว้อย่างเหมาะสมอย่างไร?
  • ความแตกต่างระหว่างสิ่งเหล่านี้คืออะไร?
  • พวกเขาเกี่ยวข้องกันอย่างไร

คำตอบ:


13

เอาล่ะเราไปทีละคนกัน

ค่า

ค่าคือชิ้นส่วนที่เป็นรูปธรรมของข้อมูลที่โปรแกรมประเมินและเล่นปาหี่ ไม่มีอะไรแฟนซีบางตัวอย่างอาจเป็น

  • 1
  • true
  • "fizz buzz foo bar"

ประเภท

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

ตัวอย่างเช่นถ้าคุณบอกฉันว่าe : boolเวลารวบรวมและฉันจะรู้ว่าeเป็นอย่างใดอย่างหนึ่งtrueหรือfalseในช่วงรันไทม์ไม่มีอะไรอื่น! เนื่องจากประเภทแบ่งประเภทค่าอย่างนี้เราสามารถใช้ข้อมูลนี้เพื่อกำหนดคุณสมบัติพื้นฐานของโปรแกรมของคุณ

ตัวอย่างเช่นถ้าฉันเคยเห็นคุณเพิ่มeและe'เวลาe : intและe' : Stringจากนั้นฉันรู้ว่าบางสิ่งบางอย่างออกไปเล็กน้อย! ในความเป็นจริงฉันสามารถตั้งค่าสถานะนี้และโยนข้อผิดพลาดในเวลารวบรวมโดยพูดว่า "เฮ้นั่นมันไม่เข้าท่าเลย!"

ระบบประเภทที่ทรงพลังยิ่งกว่าจะช่วยให้ประเภทที่น่าสนใจมากขึ้นซึ่งจำแนกค่าที่น่าสนใจมากขึ้น ตัวอย่างเช่นลองพิจารณาฟังก์ชั่นบางอย่าง

f = fun x -> x

เป็นที่ชัดเจนว่าf : Something -> Somethingแต่สิ่งที่ควรSomethingจะเป็นอย่างไร Something = intในระบบการพิมพ์ที่น่าเบื่อเราจะต้องระบุบางสิ่งบางอย่างโดยพลการเช่น ในระบบประเภทที่ยืดหยุ่นกว่านี้เราสามารถพูดได้

f : forall a. a -> a

นั่นคือการบอกว่า "สำหรับการใด ๆa, fแผนที่aไปยังa" สิ่งนี้ให้เราใช้งานได้fทั่วไปมากขึ้นและเขียนโปรแกรมที่น่าสนใจมากขึ้น

ยิ่งไปกว่านั้นคอมไพเลอร์จะตรวจสอบความพึงพอใจของลักษณนามที่เราได้รับจริงถ้าหากf = fun x -> trueเรามีข้อผิดพลาดและคอมไพเลอร์จะพูดอย่างนั้น!

ดังนั้นในฐานะ tldr; type เป็นข้อ จำกัด เวลาในการรวบรวมค่าที่ expression สามารถทำได้ในขณะทำงาน

ตัวสร้างประเภท

บางประเภทเกี่ยวข้องกัน ตัวอย่างเช่นรายการจำนวนเต็มคล้ายกับรายการสตริง นี่เป็นเหมือนวิธีsortการจำนวนเต็มเกือบจะเหมือนsortสตริง เราสามารถจินตนาการประเภทของโรงงานที่สร้างประเภทเกือบจะเหมือนกันเหล่านี้โดยการสรุปความแตกต่างและสร้างตามความต้องการ นั่นคือสิ่งที่ตัวสร้างประเภทคือ มันเป็นเหมือนฟังก์ชั่นจากประเภทถึงประเภท แต่มีข้อ จำกัด มากกว่าเล็กน้อย

ตัวอย่างคลาสสิกเป็นรายการทั่วไป ตัวสร้างประเภทสำหรับเป็นเพียงคำจำกัดความทั่วไป

 data List a = Cons a (List a) | Nil

ตอนนี้Listเป็นฟังก์ชั่นที่แมปประเภทaกับรายการค่าประเภทนั้น! ใน Java-land ฉันคิดว่าสิ่งเหล่านี้อาจเรียกว่า "คลาสทั่วไป"

พารามิเตอร์ประเภท

พารามิเตอร์ type เป็นเพียงประเภทที่ส่งผ่านไปยังตัวสร้างประเภท (หรือฟังก์ชัน) เช่นเดียวกับในระดับค่าที่เราจะบอกว่าfoo(a)มีพารามิเตอร์aเช่นเดียวกับวิธีมีพารามิเตอร์ชนิดList aa

ชนิด

ชนิดค่อนข้างยุ่งยาก แนวคิดพื้นฐานคือบางประเภทมีความคล้ายคลึงกัน ตัวอย่างเช่นเรามีทุกชนิดดั้งเดิมใน java int, char, float... ซึ่งประพฤติทุกราวกับว่าพวกเขามี "พิมพ์" เดียวกัน ยกเว้นเมื่อเราพูดถึงตัวแยกประเภทสำหรับประเภทเองเราเรียกชนิดของตัวแยกประเภท ดังนั้นint : Prim, ,String : BoxList : Boxed -> Boxed

ระบบนี้ให้กฎที่เป็นรูปธรรมที่ดีเกี่ยวกับประเภทประเภทที่เราสามารถใช้ได้ตรงที่เหมือนกับประเภทที่ควบคุมค่า เห็นได้ชัดว่ามันไร้สาระที่จะพูด

 List<List>

หรือ

 List<int>

ใน Java Listจำเป็นต้องใช้กับชนิดที่เป็นรูปธรรมเพื่อใช้เช่นนั้น! ถ้าเราดูชนิดของมันList : Boxed -> Boxedและตั้งแต่Boxed -> Boxed /= Boxedข้างต้นเป็นข้อผิดพลาดชนิด!

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

ภาพประกอบเล็ก ๆ น้อย ๆ ของสิ่งที่ฉันพูดไป

 value   : type : kind  : ...
 true    : bool : Prim  : ...
 new F() : Foo  : Boxed : ...

อ่านดีกว่าวิกิพีเดีย

หากคุณสนใจสิ่งนี้ฉันขอแนะนำให้ลงทุนในตำราเรียนที่ดี ทฤษฎีประเภทและ PLT โดยทั่วไปนั้นค่อนข้างกว้างใหญ่และไม่มีความรู้พื้นฐานที่สอดคล้องกันคุณ (หรืออย่างน้อยฉัน) สามารถเดินไปรอบ ๆ ได้โดยไม่ต้องไปไหนมาหลายเดือน

หนังสือเล่มโปรดสองเล่มของฉันคือ

  • ประเภทและภาษาการเขียนโปรแกรม - Ben Pierce
  • พื้นฐานการปฏิบัติของภาษาโปรแกรม - Bob Harper

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


1
ประเภทคือชุด? ฉันชอบ "ตัวจําแนก" ดีกว่า แต่คุณไม่ได้อธิบายความหมายนี้และหากไม่มีความเข้าใจที่ดีว่าประเภทคืออะไรคําตอบที่เหลือของคุณก็จะลดลง
Robert Harvey

@RobertHarvey อย่างไรมันดูตอนนี้ผมได้ปรับตัวลดลงทุกกล่าวถึงชุด :)
แดเนียล Gratzer

1
ดีกว่ามาก ....
Robert Harvey

@RobertHarvey ฉันพบว่ามุมมองของประเภทเป็นชุดที่ใช้งานง่ายมาก เช่นชนิดintใน Java ประกอบด้วยชุดของค่าที่แตกต่าง 2 ^ 64 การเปรียบเทียบกับชุดแบ่งย่อยเมื่อมีส่วนร่วมย่อย แต่มันก็เป็นสัญชาตญาณเริ่มต้นที่ดีโดยเฉพาะอย่างยิ่งเมื่อคุณพิจารณาประเภทข้อมูลพีชคณิต (เช่นการรวมกันของสองประเภทสามารถมีสมาชิกใด ๆ ของทั้งสองประเภทมันเป็นสหภาพของชุดเหล่านั้น) .
Doval

@Doval: ถ้าฉันเขียนคลาสที่อธิบายลูกค้ามันอาจจะเป็นตัวแทนของ "set" ของลูกค้าเนื่องจากฉันจะสร้างชุดของอินสแตนซ์ แต่การบอกว่าลูกค้าเป็นประเภทเพราะมันอธิบายถึง "ชุด" ของลูกค้าคือการพูดซ้ำซาก ดูเหมือนชัดเจน สิ่งที่น่าสนใจกว่าคือประเภทลูกค้าอธิบายถึงลักษณะของลูกค้า การใช้ "set" เพื่ออธิบายสิ่งนี้ดูเหมือนว่า ... เป็นนามธรรมมากกว่าที่เป็นจริง เว้นแต่คุณจะเป็นนักคณิตศาสตร์
Robert Harvey

2

สิ่งเหล่านี้ถูกกำหนดไว้อย่างเหมาะสมอย่างไร?

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

แต่โปรแกรมเมอร์ส่วนใหญ่ไม่จำเป็นต้องรู้สิ่งนั้น พวกเขาต้องเข้าใจแนวคิด

ค่า

เริ่มจากค่ากันก่อน ค่าคือข้อมูลที่ใช้ในการคำนวณ ขึ้นอยู่กับวิธีการที่พวกเขาคุ้นเคยกับค่าที่ทุกคนคุ้นเคย: 42, 3.14, "วัวสีน้ำตาลตอนนี้" บันทึกบุคลากรสำหรับเจนนี่ลงในการบัญชี ฯลฯ

การตีความอื่น ๆ ของค่าเป็นสัญลักษณ์ โปรแกรมเมอร์ส่วนใหญ่เข้าใจสัญลักษณ์เหล่านี้เพื่อเป็น "ค่า" ของการแจงนับ LeftและRightเป็นสัญลักษณ์สำหรับ enum Handedness(ไม่สนใจคนตีสองหน้าและปลา)

ไม่ว่าจะมีการนำไปใช้อย่างไรค่าต่าง ๆ ที่ภาษาใช้เพื่อทำการคำนวณ

ประเภท

ปัญหาเกี่ยวกับค่าคือการคำนวณทั้งหมดนั้นไม่ถูกต้องสำหรับค่าทั้งหมด 42 + goatไม่สมเหตุสมผลเลย

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

การใช้งานจริงอื่นที่ต้องพิจารณาคือภายใต้ประทุนคอมพิวเตอร์ทำงานกับไบต์ ไบต์ 42 อาจหมายถึงหมายเลข 42 หรืออาจหมายถึงอักขระ * หรืออาจหมายถึง Jenny จากการบัญชี ประเภทยัง (ในการใช้งานจริงไม่มากนัก) ช่วยกำหนดการเข้ารหัสสำหรับคอลเลกชันพื้นฐานของไบต์ที่ใช้โดยคอมพิวเตอร์

ชนิด

และนี่คือที่ที่เราเริ่มออกไปเล็กน้อย ดังนั้นเมื่อภาษาการเขียนโปรแกรมมีตัวแปรที่อ้างอิงถึงประเภทใดมันมีชนิดใด

ใน Java และ C # มีประเภทType(ซึ่งมีประเภทTypeซึ่งมี ... และอื่น ๆ ลงไป) นี่คือแนวคิดที่อยู่เบื้องหลังชนิด ในบางภาษาคุณสามารถทำสิ่งที่มีประโยชน์มากขึ้นด้วยตัวแปร Type กว่า Java และ C # หลังจากที่เกิดขึ้นมันจะกลายเป็นประโยชน์ที่จะพูดว่า "ฉันต้องการค่าที่ประเภท แต่ยังเป็นบางชนิดของIEnumerable<int>" Ta-da! ชนิด

โปรแกรมเมอร์ส่วนใหญ่สามารถนึกถึงข้อ จำกัด ต่าง ๆ เช่น Java และ C # public class Foo<T> where T: IComparable{}พิจารณา ในภาษาที่มีชนิดการT: kindOf(IComparable)ประกาศตัวแปรจะถูกกฎหมาย ไม่ใช่แค่สิ่งพิเศษที่คุณสามารถทำได้ในคลาสและการประกาศฟังก์ชัน

ประเภทก่อสร้าง

อาจจะแปลกใจประเภทการก่อสร้างเป็นเพียงการก่อสร้างงานประเภท "แต่คุณจะสร้างประเภทได้อย่างไรประเภทเป็นเพียงแค่" เอ๊ะ ... ไม่มาก

นอกจากนี้ยังแปลกใจก็ยากสวยที่จะสร้างทั้งหมดของส่วนย่อยที่มีประโยชน์ที่แตกต่างกันของค่าโปรแกรมคอมพิวเตอร์ใด ๆ เลยที่จะใช้ ตัวสร้างประเภททำงานเพื่อช่วยให้โปรแกรมเมอร์ "สร้าง" ส่วนย่อยเหล่านั้นด้วยวิธีที่มีความหมาย

int[4]ตัวอย่างที่แพร่หลายมากที่สุดของตัวสร้างประเภทคือนิยามอาร์เรย์: ที่นี่คุณกำลังระบุ4ให้กับตัวสร้างประเภทซึ่งใช้ค่าในการสร้างอาร์เรย์ของintคุณด้วย 4 รายการ หากคุณระบุประเภทอินพุตที่แตกต่างกันคุณจะได้รับประเภทเอาต์พุตอื่น

Generics เป็นรูปแบบของตัวสร้างประเภทอื่นโดยใช้ชนิดอื่นเป็นอินพุต

ในหลายภาษามีความเป็นตัวสร้างประเภทเช่นP -> Rการสร้างชนิดที่แสดงถึงฟังก์ชั่นที่ใช้ชนิดหนึ่งและผลตอบแทนประเภทPR

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

พิมพ์พารามิเตอร์

คุณจำพารามิเตอร์ที่ส่งไปยัง Type Constructors ได้ไหม? พวกเขากำลังเป็นที่รู้จักกันทั่วไปว่าเป็นประเภทพารามิเตอร์ตั้งแต่รูปแบบทั่วไปของประเภทสร้างเป็นหรือType[param]Type<param>


1
คุณช่วยอธิบาย / ขยายหัวข้อเกี่ยวกับ 'Kinds' ได้หรือไม่ ใน Haskell ชนิดมีชนิด*ในขณะที่ตัวสร้างประเภท (มีหนึ่งอาร์กิวเมนต์) * -> *มีชนิด ข้อ จำกัด เช่น(Num a) => a(หมายถึง "ประเภทใด ๆaที่เป็นตัวอย่างของตัวNumพิมพ์ดีด") ไม่ใช่ชนิดของตัวเอง typeclass Numไม่ได้เป็น 'ชนิด' ตัวเอง * -> Constraintแต่มีชนิด ฉันคิดว่ามันยากที่จะเชื่อมโยงแนวคิด Haskell ของ 'ชนิด' (ซึ่งฉันคิดว่ามีความสัมพันธ์อย่างใกล้ชิดกับชนิดในทฤษฎีประเภท?) กับตัวอย่างที่คุณให้
John Bartholomew

ฉันควรจะพูดว่า ghci ของ:kindคำสั่งให้ชนิดของการเป็นNum * -> Constraintนั่นอาจเฉพาะเจาะจงกับ GHC ฉันไม่รู้
John Bartholomew

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