ความแตกต่างระหว่างประเภทและชนิดคืออะไร


26

ฉันเรียนรู้การเขียนโปรแกรม langauge Haskell และฉันพยายามที่จะตัดหัวของฉันรอบสิ่งที่แตกต่างระหว่างที่typeและkindเป็น

a kind is a type of typeตามที่ผมเข้าใจมัน ยกตัวอย่างเช่นและa ford is a type of cara car is a kind of vehicle

นี่เป็นวิธีที่ดีที่จะคิดเกี่ยวกับสิ่งนี้หรือไม่?

เพราะวิธีการที่สมองของฉันเป็นสายในปัจจุบันเป็นford is a **type** of carแต่ยังขณะที่ในเวลาเดียวกันcar is a **type** of vehicle นั่นcar is a **kind** of vehicleคือข้อกำหนดtypeและkindสามารถใช้แทนกันได้

ใครช่วยแสงนี้บ้าง


6
ฉันเพิ่งมาที่นี่จากโพสต์บน Stack Overflow ที่นำไปสู่การสนทนานี้ ฉันไม่แน่ใจว่าฉันมีคุณสมบัติที่จะตอบในรายละเอียด - แต่คุณแน่นอนว่ามีความหมายตามตัวอักษรมากเกินไปเกี่ยวกับคำว่า "ประเภท" และ "ชนิด" ในการพยายามเชื่อมโยงพวกเขาเข้ากับความหมายของพวกเขาในภาษาอังกฤษ ) คุณควรปฏิบัติต่อพวกเขาเป็นข้อตกลงทางเทคนิค "Type" เป็นที่เข้าใจกันดีโดยโปรแกรมเมอร์ทุกคนฉันถือว่าเพราะแนวคิดนี้มีความสำคัญต่อทุกภาษาแม้แต่คนที่มีความอ่อนแอเช่น Javascript "Kind" เป็นคำศัพท์ทางเทคนิคที่ใช้ใน Haskell สำหรับ "type of a type" นั่นคือทั้งหมดที่มีให้มัน
Robin Zigmond

2
@RobinZigmond: คุณพูดถูกว่าเป็นศัพท์เทคนิค แต่มันถูกใช้อย่างกว้างขวางมากกว่าใน Haskell อาจจะลิงก์ย้อนกลับไปยังการสนทนา Stack Overflow ที่ให้กำเนิดคำถามนี้
Andrej Bauer

@ AndrejBauer ฉันไม่เคยพูดว่าพวกเขาไม่ได้ใช้นอก Haskell แน่นอนว่า "type" ถูกใช้ในทุกภาษาเป็นหลักตามที่ฉันพูด ฉันไม่เคยเจอ "ใจดี" นอกแฮสเค็ล แต่จริง ๆ แล้วแฮสเค็ลล์เป็นภาษาที่ใช้งานได้เพียงอย่างเดียวที่ฉันรู้จักและฉันก็ระวังไม่พูดคำที่ไม่ได้ใช้ที่อื่น แต่ใช้ในลักษณะนั้น Haskell (และลิงก์ตามที่คุณร้องขออยู่ที่นี่ )
Robin Zigmond

ภาษาตระกูล ML มีหลายภาษาเช่น Standard ML และ OCaml ฉันคิดว่าพวกเขาไม่ได้เปิดเผยอย่างชัดเจนจากชื่อนั้น พวกเขาจะประจักษ์เป็นลายเซ็นและองค์ประกอบของพวกเขาจะเรียกว่าโครงสร้าง
Andrej Bauer

1
การเปรียบเทียบภาษาอังกฤษที่แม่นยำยิ่งขึ้นคือฟอร์ดเป็นประเภทของรถยนต์และรถยนต์เป็นยานพาหนะ แต่ประเภทของรถยนต์และประเภทของยานพาหนะเป็นประเภทเดียวกัน: คำนาม ในขณะที่สีแดงเป็นสีรถชนิดหนึ่งและ RPM เป็นมาตรวัดประสิทธิภาพรถยนต์ประเภทหนึ่งและทั้งสองประเภทเดียวกันคือคำคุณศัพท์
Slebetman

คำตอบ:


32

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

คำตอบของฉันเกี่ยวข้องกับความหมายอย่างเป็นทางการของข้อกำหนดเหล่านี้ในบริบทของ Haskell โดยเฉพาะ ความหมายเหล่านี้มีพื้นฐานมาจาก (แม้ว่าจะไม่เหมือนกันจริง ๆ ) ความหมายที่ใช้ในทางคณิตศาสตร์ / CS "ทฤษฎีประเภท" ดังนั้นนี่จะไม่ใช่คำตอบที่ดีมาก "วิทยาการคอมพิวเตอร์" แต่ควรเป็นคำตอบที่ดีสำหรับ Haskell

ใน Haskell (และภาษาอื่น ๆ ) มันจะมีประโยชน์ในการกำหนดประเภทให้กับนิพจน์โปรแกรมที่อธิบายคลาสของค่าที่นิพจน์ได้รับอนุญาต ฉันคิดว่าที่นี่คุณได้เห็นตัวอย่างเพียงพอที่จะเข้าใจว่าทำไมมันจะมีประโยชน์ที่จะรู้ว่าในการแสดงออกsqrt (a**2 + b**2)ตัวแปรaและbจะเป็นค่าประเภทเสมอDoubleและไม่พูดStringและBoolตามลำดับ โดยทั่วไปมีประเภทช่วยให้เราในการเขียนการแสดงออก / โปรแกรมที่จะทำงานได้อย่างถูกต้องในช่วงกว้างของค่า

ทีนี้บางสิ่งที่คุณอาจไม่เคยรู้มาก่อนก็คือประเภท Haskell เช่นเดียวกับที่ปรากฏในลายเซ็นประเภท:

fmap :: Functor f => (a -> b) -> f a -> f b

จริง ๆ แล้วตัวเองเขียนในภาษาย่อยระดับ Haskell ข้อความของโปรแกรมFunctor f => (a -> b) -> f a -> f bคือ - ค่อนข้างแท้จริง - นิพจน์ประเภทที่เขียนในภาษาย่อยนี้ sublanguage รวมถึงผู้ประกอบการ (เช่น->เป็นผู้ประกอบการมัดขวาเชื่อมโยงในภาษานี้) ตัวแปร (เช่นf, aและb) และ "แอพลิเคชัน" ของการแสดงออกประเภทหนึ่งไปยังอีก (เช่นf aถูกfนำไปใช้a)

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

ดังนั้นค่าจะประเภทเป็นชนิดจะชนิดและประเภทช่วยให้เราเขียนค่าโปรแกรมระดับพื้นดินในขณะที่ชนิดช่วยให้เราเขียนพิมพ์โปรแกรมระดับพื้นดิน

สิ่งใดที่เหล่านี้ชนิดมีลักษณะอย่างไร ลองพิจารณาประเภทของลายเซ็น:

id :: a -> a

หากแสดงออกประเภทa -> aคือการถูกต้องสิ่งที่ชนิดของประเภทที่เราควรจะอนุญาตให้มีตัวแปรaจะเป็น? นิพจน์ประเภท:

Int -> Int
Bool -> Bool

มีลักษณะที่ถูกต้องดังนั้นประเภท IntและBoolจะเห็นได้ชัดทางด้านขวาชนิด แต่ประเภทที่ซับซ้อนยิ่งขึ้นเช่น:

[Double] -> [Double]
Maybe [(Double,Int)] -> Maybe [(Double,Int)]

ดูถูกต้อง ในความเป็นจริงเนื่องจากเราควรจะสามารถเรียกidใช้ฟังก์ชันได้:

(a -> a) -> (a -> a)

ดูดี ดังนั้นInt, Bool, [Double], Maybe [(Double,Int)]และa -> aรูปลักษณ์ทั้งหมดเช่นประเภทของสิทธิชนิด

ในคำอื่น ๆ ที่ดูเหมือนว่ามีเพียงหนึ่งชนิดขอเรียกมัน*เหมือนตัวแทน Unix และทุกประเภทมีเดียวกันชนิด * , ตอนจบของเรื่อง

ขวา?

ก็ไม่มาก ปรากฎว่าMaybeทั้งหมดโดยตัวมันเองเป็นเพียงการแสดงออกประเภทที่ถูกต้องเป็นMaybe Int(ในทางเดียวกันsqrtมากโดยตัวเองทั้งหมดเป็นเพียงการแสดงออกที่ถูกต้องค่าเป็นsqrt 25) อย่างไรก็ตามการแสดงออกประเภทต่อไปนี้ไม่ถูกต้อง:

Maybe -> Maybe

เนื่องจากในขณะที่Maybeเป็นนิพจน์ประเภทจึงไม่ได้แสดงประเภทของประเภทที่สามารถมีค่าได้ ดังนั้นนั่นคือวิธีการที่เราควรกำหนด*- เป็นชนิดของประเภทที่มีค่า; มันรวมถึงประเภท "สมบูรณ์" ชอบDoubleหรือแต่ไม่รวมที่ไม่สมบูรณ์แบบไร้ค่าเช่นMaybe [(Double,Int)] Either Stringเพื่อความเรียบง่ายฉันจะเรียก*"คอนกรีตประเภท" ประเภทนี้อย่างสมบูรณ์แม้ว่าคำศัพท์นี้จะไม่เป็นสากลและ "คอนกรีตประเภท" อาจหมายถึงสิ่งที่แตกต่างจากโปรแกรมเมอร์ C ++

ตอนนี้ในการแสดงออกของชนิดa -> aตราบเท่าที่ประเภทaมีชนิด * (ชนิดของประเภทคอนกรีต) ผลของการแสดงออกประเภทที่a -> aจะยังมีชนิด * (เช่นชนิดของประเภทคอนกรีต)

ดังนั้นสิ่งที่ชนิดของประเภทคือMaybe? ดีMaybeสามารถนำไปใช้ประเภทคอนกรีตเพื่อให้คอนกรีตชนิดอื่น ดังนั้นMaybeดูเหมือนเล็กน้อยเช่นฟังก์ชั่นประเภทในระดับที่ใช้เป็นชนิดของชนิด *และผลตอบแทนประเภทของชนิด *ถ้าเรามีฟังก์ชั่นระดับค่าที่เอาค่าของประเภท Intและส่งกลับค่าของประเภท Intที่เราต้องการให้มันเป็นประเภทลายเซ็นInt -> Intดังนั้นโดยการเปรียบเทียบเราควรจะให้ชนิดลายเซ็น GHCi เห็นด้วย:Maybe* -> *

> :kind Maybe
Maybe :: * -> *

กลับไปที่:

fmap :: Functor f => (a -> b) -> f a -> f b

ในลายเซ็นของประเภทนี้ตัวแปรfมีชนิด* -> *และตัวแปรaและbมีชนิด*; ตัวดำเนินการในตัว->มีชนิด* -> * -> *(ใช้ชนิดของชนิด*ด้านซ้ายและด้านขวาและส่งชนิดชนิด*) จากนี้และกฎระเบียบของการอนุมานชนิดที่คุณสามารถอนุมานได้ว่าa -> bเป็นชนิดที่ถูกต้องกับทุกชนิด*, f aและf bนอกจากนี้ยังมีประเภทที่ถูกต้องกับทุกชนิด*และเป็นประเภทที่ถูกต้องของชนิด(a -> b) -> f a -> f b*

กล่าวอีกนัยหนึ่งคอมไพเลอร์สามารถ "ตรวจสอบชนิด" นิพจน์ประเภท(a -> b) -> f a -> f bเพื่อตรวจสอบว่ามันถูกต้องสำหรับตัวแปรประเภทของชนิดที่ถูกต้องเช่นเดียวกับ "ตรวจสอบประเภท" sqrt (a**2 + b**2)เพื่อตรวจสอบว่าถูกต้องสำหรับตัวแปรประเภทที่เหมาะสม

เหตุผลในการใช้คำที่แยกต่างหากสำหรับ "ประเภท" กับ "ชนิด" (กล่าวคือไม่ได้พูดถึง "ประเภทประเภท") ส่วนใหญ่เป็นเพียงเพื่อหลีกเลี่ยงความสับสน ชนิดข้างต้นดูแตกต่างจากชนิดและอย่างน้อยในตอนแรกดูเหมือนจะประพฤติค่อนข้างแตกต่างกัน (ยกตัวอย่างเช่นมันต้องใช้เวลาที่จะตัดหัวของรอบความคิดที่ว่าทุกประเภท "ปกติ" มีชนิดเดียวกัน*และชนิดของการa -> bเป็น*ไม่ได้* -> *.)

บางส่วนนี้เป็นประวัติศาสตร์ เมื่อ GHC Haskell มีวิวัฒนาการความแตกต่างระหว่างค่าประเภทและชนิดเริ่มเบลอ วันนี้ค่าสามารถ "เลื่อน" เป็นประเภทและประเภทและชนิดเป็นสิ่งเดียวกัน ดังนั้นใน Haskell สมัยใหม่ค่านิยมทั้งสองประเภทและประเภทARE (เกือบ) และประเภทประเภทเป็นประเภทเพิ่มเติม

@ user21820 ถามถึงคำอธิบายเพิ่มเติมของ "ประเภทและชนิดเป็นสิ่งเดียวกัน" เพื่อความชัดเจนเล็กน้อยใน GHC Haskell สมัยใหม่ (ตั้งแต่เวอร์ชั่น 8.0.1 ฉันคิดว่า) ประเภทและชนิดนั้นได้รับการปฏิบัติเหมือนกันในคอมไพเลอร์โค้ดส่วนใหญ่ คอมไพเลอร์ใช้ความพยายามในข้อความแสดงข้อผิดพลาดเพื่อแยกความแตกต่างระหว่าง "ประเภท" และ "ชนิด" ขึ้นอยู่กับว่ามันบ่นเกี่ยวกับประเภทของค่าหรือประเภทของประเภทตามลำดับ

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

แต่ถ้าคุณเปิดส่วนขยายที่เหมาะสมความแตกต่างระหว่างประเภทและชนิดส่วนใหญ่จะหายไป ตัวอย่างเช่น:

{-# LANGUAGE GADTs, TypeInType #-}
data Foo where
  Bar :: Bool -> * -> Foo

นี่Barคือ (ทั้งค่าและ) ประเภท ในฐานะที่เป็นประเภทชนิดของมันBool -> * -> Fooซึ่งเป็นฟังก์ชั่นประเภทในระดับที่ใช้ประเภทของชนิดBool(ซึ่งเป็นชนิด แต่ยังชนิด) และชนิดของชนิดและผลิตประเภทของชนิด* Fooดังนั้น:

type MyBar = Bar True Int

ตรวจสอบชนิดอย่างถูกต้อง

ในฐานะที่เป็น @AndrejBauer อธิบายในคำตอบของเขาความล้มเหลวในการแยกแยะความแตกต่างระหว่างประเภทและชนิดนี้ไม่ปลอดภัย - การมีประเภท / ชนิด*ที่มีประเภท / ชนิดเป็นตัวเอง (ซึ่งเป็นกรณีใน Haskell ทันสมัย) นำไปสู่ความขัดแย้ง อย่างไรก็ตามระบบประเภทของ Haskell นั้นเต็มไปด้วยความขัดแย้งอยู่แล้วเนื่องจากการไม่เลิกจ้างดังนั้นจึงไม่ถือว่าเป็นเรื่องใหญ่


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

1
@ user21820 ฉันเพิ่มบันทึกไปยังจุดสิ้นสุดที่อาจกล่าวถึงเรื่องนี้ คำตอบสั้น ๆ : มีไม่ได้จริงๆความแตกต่างในปัจจุบัน GHC Haskell
KA Buhr

1
นี่คือคำตอบที่ดี - ขอบคุณมากสำหรับการแบ่งปัน มันเขียนได้ดีและแนะนำแนวคิดทีละน้อย - ในฐานะคนที่ไม่ได้เขียน Haskell มาสองสามปีนี่เป็นสิ่งที่น่าชื่นชมมาก!
ultrafez

@KABuhr: ขอบคุณสำหรับบิตที่เพิ่มเข้ามา!
user21820

19

เสื้อYพีอี:kผมnd=sอีเสื้อ:ล.ass.

  • Bool เป็นประเภท
  • Type เป็นชนิดเพราะองค์ประกอบเป็นประเภท
  • Bool -> Int เป็นประเภท
  • Bool -> Type เป็นชนิดเนื่องจากองค์ประกอบเป็นฟังก์ชันที่ส่งคืนชนิด
  • Bool * Int เป็นประเภท
  • Bool * Type เป็นชนิดเนื่องจากองค์ประกอบเป็นคู่กับองค์ประกอบหนึ่งชนิด

ยู0ยู1ยู2ยู0Bโอโอล.ยังไม่มีข้อความaเสื้อยังไม่มีข้อความaเสื้อยังไม่มีข้อความaเสื้อยู1ยู0Bโอโอล.ยู0ยู0ยู0ยูn+1ยูnยูn×

ยู0ยู1ยู0ยู1ยู0**U_1


2
ฉันไม่คิดว่า (GHC) Haskell มีแนวคิดเกี่ยวกับจักรวาล Type :: Typeเป็นสัจพจน์ ความแตกต่างระหว่าง "ประเภท" และ "ประเภท" นั้นเป็นภาษามนุษย์โดยสิ้นเชิงในกรณีนี้ Trueมีประเภทที่BoolและBoolมีชนิดที่ตัวเองมีประเภทType Typeบางครั้งเราเรียกประเภทของประเภทเพื่อเน้นว่ามันเป็นประเภทของเอนทิตีระดับประเภท แต่ใน Haskell ก็ยังคงเป็นเพียงประเภท ในระบบที่จักรวาลมีอยู่จริงเช่น Coq ดังนั้น "ประเภท" อาจหมายถึงจักรวาลหนึ่งและ "ชนิด" ไปยังอีกจักรวาลหนึ่ง แต่จากนั้นเรามักจะต้องการจักรวาลจำนวนมากอย่างไม่ จำกัด
HTNW

1
ความแตกต่างไม่ใช่แค่ "ภาษามนุษย์" แต่เป็นความแตกต่างอย่างเป็นทางการในระบบการพิมพ์พื้นฐาน ค่อนข้างเป็นไปได้ที่จะมีทั้งType :: Typeความแตกต่างระหว่างชนิดและชนิด นอกจากนี้โค้ดอะไรบ้างที่แสดงให้เห็นType :: Typeใน Haskell
Andrej Bauer

1
ฉันควรจะบอกว่า*ใน Haskell เป็นจักรวาลที่แปลกประหลาด พวกเขาไม่เรียกมันว่า
Andrej Bauer

3
@AndrejBauer TypeจากData.Kindsและ*ควรเป็นคำพ้องความหมาย ตอนแรกเรามีเพียง*เป็นดั้งเดิมในขณะที่ในปัจจุบันที่กำหนดไว้ภายในเป็นGHC.Types.Typeในโมดูลภายในในการเปิดการกำหนดเป็นGHC.Types type Type = TYPE LiftedRepฉันคิดว่าTYPEเป็นสิ่งดั้งเดิมที่แท้จริงให้ครอบครัวในรูปแบบต่างๆ (แบบยก, แบบไม่มีกล่อง, ... ) ความซับซ้อน "ไม่เหมาะสม" ส่วนใหญ่ที่นี่คือการสนับสนุนการเพิ่มประสิทธิภาพระดับต่ำบางอย่างและไม่ใช่เหตุผลทางทฤษฎีประเภทจริง
Chi

1
ฉันจะพยายามสรุป ถ้าเป็นค่าแล้วก็มีประเภท:v v :: Tถ้าTT :: Kเป็นชนิดที่แล้วก็มีประเภท: ประเภทของประเภทที่เรียกว่าชนิดของมัน ประเภทที่มีลักษณะคล้ายกันTYPE repอาจเรียกว่าแปลก ๆ แม้ว่าคำนั้นจะผิดปกติ IFF T :: TYPE repจะTได้รับอนุญาตให้ปรากฏบน RHS ::ของ คำว่า "ชนิด" มีแตกต่างกันนิดหน่อยกับมัน: KในT :: Kเป็นชนิด แต่ไม่ได้อยู่ในแม้ว่ามันจะเหมือนกันv :: K Kเราสามารถนิยาม " Kเป็นชนิดหากชนิดเป็นประเภท" aka "อยู่ใน RHS ของ::" แต่นั่นไม่ได้จับการใช้งานอย่างถูกต้อง ดังนั้นตำแหน่ง "ความแตกต่างของมนุษย์" ของฉัน
HTNW

5

ค่าเป็นเหมือนเฉพาะสีแดง 2011 ฟอร์ดมัสแตงกับ 19,206 ไมล์ในนั้นที่คุณได้นั่งอยู่ในถนนของคุณ

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

(ใน Haskell เพื่อประมาณอันดับแรก (GADTs ทำลายคุณสมบัตินี้และเวทมนตร์รอบตัวอักษรจำนวนมากและส่วนขยาย OverloadedStrings ปิดบังมันเล็กน้อย) ค่ามีประเภทหลักหนึ่งประเภทแทนที่จะเป็น "ประเภท" ที่ไม่เป็นทางการคุณสามารถให้ ' stang. 42คือเพื่อวัตถุประสงค์ในการอธิบายนี้และIntไม่มีประเภทใน Haskell สำหรับ "ตัวเลข" หรือ "จำนวนเต็มคู่" หรือคุณสามารถสร้างได้ แต่จะเป็นประเภทที่แยกออกจากIntกัน)

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

(อีกครั้ง Haskell รับรู้เพียงหนึ่งชนิดสำหรับสิ่งที่แต่ละประเภทระดับดังนั้นIntมีชนิด*และไม่มีชนิดอื่น ๆMaybeมีชนิด* -> *และไม่มีชนิดอื่น ๆ แต่สัญชาตญาณควรยังคง: 42เป็นIntและคุณสามารถทำIntสิ่ง y กับมัน เช่นการเพิ่มและลบIntตัวมันเองไม่ได้Intเป็นเช่นInt + Intนั้นคุณอาจได้ยินคนพูดว่านั่นIntคือสิ่งNumที่พวกเขาหมายถึงว่ามีอินสแตนซ์ของNumคลาสประเภทสำหรับประเภทIntนี้ - ซึ่งไม่ใช่สิ่งเดียวกัน ที่บอกว่าIntมีชนิด Num . Intมีชนิด "ประเภท" ซึ่งใน Haskell สะกด*.)

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

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

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

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

(ในทำนองเดียวกันเมื่อเราพูดว่าMaybeมีเมตตา* -> *ใน Haskell เราหมายถึงว่ามันไร้สาระ (เป็นทางการ; อย่างไม่เป็นทางการเราทำตลอดเวลา) เพื่อพูดคุยเกี่ยวกับการมี "a Maybe" แทนเราสามารถมีMaybe IntหรือMaybe Stringเพราะสิ่งเหล่านั้นเป็น ชนิด*)

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


1
ฉันไม่ได้บอกว่าการเปรียบเทียบของคุณผิด แต่ฉันคิดว่ามันอาจทำให้เกิดความสับสน Dijkstra มีคำบางคำเกี่ยวกับการเปรียบเทียบ Google "ในความโหดร้ายของการสอนวิทยาศาสตร์คอมพิวเตอร์จริงๆ"
Rafael Castro

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

1

อย่างที่ฉันเข้าใจมันเป็นประเภทของประเภท

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

เราบอกว่าMaybe aเป็นตัวสร้างประเภทเพราะมันเป็นฟังก์ชั่นที่ใช้คอนกรีตประเภทเดียว (เช่นText) และส่งกลับประเภทคอนกรีต ( Maybe Textในกรณีนี้) แต่คอนสตรัคเตอร์ประเภทอื่นอาจใช้ "params อินพุท" มากกว่าเดิมก่อนที่จะส่งคืนประเภทคอนกรีต เช่นMap k vต้องใช้คอนกรีตสองประเภท (เช่นIntและText) ก่อนจึงจะสามารถสร้างคอนกรีตได้ ( Map Int Text)

ดังนั้นการMaybe aและList aประเภทมี "ลายเซ็น" เดียวกันซึ่งเราแสดงว่าเป็น* -> *(คล้ายกับลายเซ็นของฟังก์ชั่น Haskell) เพราะถ้าคุณให้คอนกรีตประเภทหนึ่งพวกเขาพวกเขาจะคายประเภทคอนกรีต เราเรียกสิ่งนี้ว่า "ชนิด" ของประเภทMaybeและListมีชนิดเดียวกัน

ชนิดคอนกรีตนั้นถูกบอกว่ามีชนิด*และตัวอย่างแผนที่ของเรานั้นเป็นชนิด* -> * -> *เพราะใช้คอนกรีตสองชนิดเป็นอินพุตก่อนที่มันจะสามารถส่งออกประเภทคอนกรีตได้

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

หากคุณเป็น Scala / Java dev คุณอาจพบว่าคำอธิบายนี้เป็นประโยชน์: https://www.atlassian.com/blog/archives/scala-types-of-a-higher-kind


สิ่งนี้ไม่ถูกต้อง ใน Haskell เราแยกแยะความแตกต่างระหว่างMaybe a, ไวพจน์สำหรับforall a. Maybe aประเภท polymorphic ของชนิด*และMaybeประเภท monomorphic * -> *ของชนิด
b0fh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.