ผลรวมประเภท - ทำไมใน Haskell จึงเป็น `show (Int | Double)` ต่างจาก `(show Int) | (แสดงสองครั้ง) `


9

ทำไมสิ่งเหล่านี้จึงไม่เทียบเท่ากัน

show $ if someCondition then someInt else some double

และ

if someCondition then show someInt else show someDouble

ฉันเข้าใจว่าถ้าคุณแยกif ... elseส่วนในตัวอย่างแรกให้กับนิพจน์ด้วยตัวเองคุณจะไม่สามารถแสดงประเภทของมันด้วยประเภทผลรวมนิรนามชนิดของInt | Doubleสิ่งที่คุณสามารถทำได้อย่างง่ายดายใน TypeScript (กล่าวถึง TypeScript เพราะมันเป็น langauge ผมใช้บ่อยและประเภทสนับสนุนซำ) และจะต้องหันไปใช้ข้อมูลนั้นขึ้นอยู่กับว่ามันจะเรียกEithershow

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

ในใจของฉันมันควรจะง่ายสำหรับคอมไพเลอร์เพื่อตรวจสอบว่าแต่ละประเภทที่ทำให้ผลรวมประเภท (ที่นี่Int | Double) สามารถใช้เป็นพารามิเตอร์ในการshowทำงานและตัดสินใจว่าประเภทถูกต้องหรือไม่ ยิ่งไปกว่านั้นshowฟังก์ชั่นนั้นจะส่งคืนstringชนิดพารามิเตอร์เสมอดังนั้นคอมไพเลอร์ไม่จำเป็นต้องดำเนินการกับ "สาขา" ที่เป็นไปได้ทั้งหมด (ดังนั้นประเภทที่เป็นไปได้ทั้งหมด)

โดยการเลือกว่าคุณสมบัติดังกล่าวไม่ได้อยู่? หรือฉันคิดว่าการนำมันไปใช้ยากขึ้น?


2
และif ... then ... else ...จำเป็นต้องมีประเภทเดียวกันในส่วนthenและ elseคุณสามารถเห็นมันเป็นผู้ประกอบการที่ประกอบไปด้วยสามภาษาการเขียนโปรแกรม
Willem Van Onsem

1
making all conversions explicitผมเห็นด้วยเกี่ยวกับ ในคำถามของฉันฉันไม่ต้องการให้ Haskell ส่งIntไปDoubleหรือกลับกัน ฉันเพิ่งใช้ทั้งสองประเภทเป็นตัวอย่าง คุณสามารถเปลี่ยนทุกIntที่มีaและDoubleที่มีในคำถามของฉันที่ได้รับมาทั้งสองประเภทb Showฉันเข้าใจว่าไม่มีanonymous sum typesใน Haskell แต่ฉันอยากจะรู้ว่าทำไมเป็นเช่นนั้นและอะไรที่ทำให้เราไม่สามารถออกแบบภาษาให้มีได้
Mehdi Saffar

4
ผมคิดว่าประเภทดังกล่าวจะเรียกว่าประเภทยูเนี่ยน ประเภทผลรวมนั้นเป็นตัวแปรที่ติดแท็กประเภทสหภาพโดยที่แต่ละค่าจะต้องมีแท็กซ้าย / ขวาเกินกว่าค่าของประเภทภายใน ฉันคาดว่าการอนุมานประเภทนั้นกับประเภทสหภาพด้วยคุณสมบัติระดับประเภททั้งหมดของ Haskell นั้นทำได้ยากมาก ถ้าx :: Int | Boolและเราต้องคอมไพล์show xก็ไม่มีวิธีที่ง่ายที่จะรู้ว่าตัวชี้ไปยังฟังก์ชันใดที่จะใช้สำหรับการโทรshowใน RTS แบบลบประเภท เราอาจต้องเก็บข้อมูลระดับประเภทไว้ที่รันไทม์
Chi

1
การไม่มีประเภทผลรวมนิรนามเป็นการตัดสินใจออกแบบของนักออกแบบ Haskell ฉันไม่แน่ใจว่าพวกเขาจะได้ประโยชน์อะไรบ้างจากโต๊ะฉันจะเห็นว่าพวกเขาจะทำให้สิ่งต่าง ๆ ซับซ้อนขึ้นได้อย่างไร ดังนั้นฉันเดาว่าพวกเขาจะถูกทิ้งไว้เพราะอัตราส่วนค่าใช้จ่าย / ผลประโยชน์ไม่ได้มี แต่เพื่อให้แน่ใจว่าคุณจะต้องถามนักออกแบบภาษาดั้งเดิมและ / หรือผู้ดูแลปัจจุบัน ฉันไม่คิดว่ามันจะเป็นคำถามที่ดีมากเพราะมีความคิดเห็นส่วนตัวและรสนิยมที่เกี่ยวข้องในการออกแบบภาษา
n คำสรรพนาม 'm

4
(String, Int)ไม่ระบุชื่อ มันเป็นเพียงประเภทผลิตภัณฑ์ปกติที่มีไวยากรณ์ตลก (String | Int)จะแตกต่างกันมากทั้ง เริ่มต้นด้วยการถามตัวเองว่า(Int|Int)ควรจะเหมือนกันIntและทำไม
n คำสรรพนาม 'm

คำตอบ:


8

ทุกส่วนของนิพจน์ต้องพิมพ์อย่างถูกต้อง ประเภทของif someCondition then someInt else someDoubleจะต้องเป็นสิ่งที่ต้องการexists a. Show a => aแต่ Haskell ไม่สนับสนุนการระบุปริมาณแบบนั้น

อัปเดต: ตามที่ชีชี้ให้เห็นในความคิดเห็นสิ่งนี้อาจเป็นไปได้ถ้า Haskell มีการสนับสนุนประเภทยูเนี่ยน / ทางแยก (ซึ่งไม่เหมือนกับประเภทผลรวม / ผลิตภัณฑ์) แต่น่าเสียดายที่ไม่มี


คุณช่วยอธิบายรายละเอียดเกี่ยวกับความแตกต่างระหว่างประเภทยูเนี่ยน / ทางแยกและประเภทรวม / ผลิตภัณฑ์ได้หรือไม่ ฉันคิดเสมอว่าพวกเขาเหมือนกันยกเว้นการไม่เปิดเผยตัวตน?
Mehdi Saffar

1
@MehdiSaffar ไม่ประสงค์ออกนามเหมือนในแท็กไม่ได้อยู่ในคอนสตรัคเตอร์ที่ไม่มีชื่อ กล่าวอีกนัยหนึ่งถ้าคุณมีInt ∪ Doubleแล้วคุณจะรู้ว่าคุณมีหนึ่งในสอง แต่จะไม่สามารถจับคู่รูปแบบเพื่อดูว่าดังนั้นคุณสามารถทำสิ่งที่จะถูกต้องเพื่อความเป็นไปได้ทั้งสอง
Joseph Sible-Reinstate Monica

2
เพื่อความชัดเจน TypeScript มีข้อมูลประเภทที่รันไทม์ดังนั้นจึงมีtypeofโอเปอเรเตอร์ที่สามารถชดเชยการขาดการติดแท็กและดูว่ามีการใช้ประเภทใดอยู่ Haskell นั้นถูกลบประเภทอย่างสมบูรณ์ดังนั้นหากรองรับคุณสมบัตินี้แสดงว่าไม่มีสิ่งใดเทียบเท่าได้
Joseph Sible-Reinstate Monica

7

มีประเภทผลิตภัณฑ์ที่มีไวยากรณ์น้ำหนักเบาเป็นลายลักษณ์อักษร(,)ใน Haskell สิ่งหนึ่งที่ประเภทผลรวมกับไวยากรณ์ที่มีน้ำหนักเบา(Int | String)จะเป็นความคิดที่ดี ความจริงมีความซับซ้อนมากขึ้น มาดูกันว่าทำไม (ฉันใช้เสรีภาพบางอย่างNumมันไม่สำคัญ)

if someCondition then 42 else "helloWorld"

หากสิ่งนี้ควรส่งคืนค่าที่มีประเภทเหมือน(Int | String)ดังนั้นสิ่งที่ควรกลับมาดังต่อไปนี้?

if someCondition then 42 else 0

(Int | Int)เห็นได้ชัด แต่ถ้าสิ่งนี้แตกต่างจากธรรมดาIntเราก็มีปัญหาลึก ดังนั้นควรจะเหมือนกับธรรมดา(Int | Int)Int

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

ลองดูฟังก์ชั่นนี้

mysteryType x a b = if x then a else b

ตอนนี้ประเภทใดmysteryTypeมี? อย่างชัดเจน

mysteryType :: Bool -> a -> b -> (a|b)

ขวา? ตอนนี้จะเกิดอะไรขึ้นถ้าaและbเป็นประเภทเดียวกัน

let x = mysteryType True 42 0

นี่ควรเป็นเรื่องธรรมดาIntตามที่เราได้ตกลงกันไว้ก่อนหน้านี้ ตอนนี้mysteryTypeบางครั้งส่งคืนผลรวมที่ไม่ระบุตัวตนและบางครั้งก็ไม่ได้ขึ้นอยู่กับว่าคุณผ่านการโต้แย้งอะไร รูปแบบที่คุณจะจับคู่การแสดงออกเช่นนั้นได้อย่างไร คุณทำอะไรกับโลกนี้ได้บ้าง? ยกเว้นสิ่งเล็กน้อยเช่น "แสดง" (หรือวิธีการใด ๆ ของคลาสประเภทอื่น ๆ มันจะเป็นตัวอย่างของ) ไม่มาก หากคุณไม่เพิ่มข้อมูลประเภทเวลาทำงานลงในภาษากล่าวคือtypeofมีอยู่ - และทำให้ Haskell เป็นภาษาที่แตกต่างอย่างสิ้นเชิง

ใช่แล้ว ทำไม Haskell ไม่ใช่ TypeScript? เพราะเราไม่ต้องการ TypeScript อื่น หากคุณต้องการ TypeScript คุณรู้ว่าจะหาได้จากที่ไหน


1
@MichaWiedenmann ตรงไปตรงมาฉันไม่รู้ว่า "ที่เกี่ยวข้อง" เป็นคำที่เหมาะสมหรือไม่ ฉันคิดว่ามันมีประโยชน์ไม่ทางใดก็ทางหนึ่ง ใช่ฉันหยุดสักครู่แล้วคิดว่าจะรวมไว้หรือไม่ แต่ฉันรู้ว่าผิดครั้ง
n คำสรรพนาม 'm

ไม่มีปัญหาโพสต์ของคุณคือคุณตัดสินใจ
Micha Wiedenmann

ดังนั้นสรรพนามของคุณคืออะไร?
dfeuer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.