การอนุมานประเภทใน Golang / Haskell


9

ฉันอ่านแล้วว่า Go ไม่มีการอนุมานแบบจริงในแง่ที่ภาษาที่ใช้งานได้เช่น ML หรือ Haskell มี แต่ฉันไม่สามารถหาคำเปรียบเทียบที่เข้าใจได้ง่ายของทั้งสองเวอร์ชัน ใครสามารถอธิบายในแง่พื้นฐานว่าการอนุมานใน Go นั้นแตกต่างจากการอนุมานประเภทใน Haskell และข้อดี / ข้อเสียของแต่ละคนอย่างไร

คำตอบ:


13

ดูคำตอบ StackOverflowนี้เกี่ยวกับการอนุมานประเภทของ Go ฉันไม่คุ้นเคยกับตัวเองไป แต่ขึ้นอยู่กับคำตอบนี้ดูเหมือนว่า "การลดประเภท" แบบทางเดียว (เพื่อยืมบาง C ++ teminology) หมายความว่าถ้าคุณมี:

x := y + z

จากนั้นประเภทของการxอนุมานโดยการหาประเภทของy + zซึ่งเป็นสิ่งที่ค่อนข้างน่าสนใจสำหรับคอมไพเลอร์ ในการทำเช่นนี้ประเภทของyและzจำเป็นต้องรู้ก่อน : สามารถทำได้ผ่านคำอธิบายประกอบประเภทหรืออนุมานจากตัวอักษรที่กำหนดให้พวกเขา


ในทางตรงกันข้ามภาษาที่ใช้งานได้ส่วนใหญ่มีการอนุมานประเภทที่ใช้ข้อมูลที่เป็นไปได้ทั้งหมดภายในโมดูล (หรือฟังก์ชั่นหากอัลกอริทึมการอนุมานเป็นแบบโลคัล) เพื่อรับประเภทของตัวแปร อัลกอริธึมการอนุมานที่ซับซ้อน (เช่น Hindley-Milner) มักจะเกี่ยวข้องกับรูปแบบการรวมกันบางประเภท(เล็กน้อยเช่นการแก้สมการ) ที่อยู่เบื้องหลัง ตัวอย่างเช่นใน Haskell ถ้าคุณเขียน:

let x = y + z

แล้ว Haskell สามารถอนุมานชนิดไม่เพียงxแต่ยังyและzอยู่บนพื้นฐานของความเป็นจริงเพียงว่าคุณมีประสิทธิภาพนอกจากนี้ในพวกเขา ในกรณีนี้:

x :: Num a => a
y :: Num a => a
z :: Num a => a

(ตัวพิมพ์เล็กaที่นี่หมายถึงประเภท polymorphicมักจะเรียกว่า "generics" ในภาษาอื่นเช่น C ++ Num a =>ส่วนที่เป็นข้อ จำกัดเพื่อระบุว่าการaสนับสนุนประเภทมีความคิดบางอย่างของการเพิ่ม)

นี่คือตัวอย่างที่น่าสนใจมากขึ้น: combinator แบบคงที่ที่อนุญาตให้ฟังก์ชัน recursive ใด ๆ ถูกกำหนด:

let fix f = f (fix f)

ขอให้สังเกตว่าเราไม่ได้ระบุประเภทของfหรือไม่ได้ระบุประเภทของfixแต่คอมไพเลอร์ Haskell สามารถคิดได้โดยอัตโนมัติว่า:

f :: t -> t
fix :: (t -> t) -> t

สิ่งนี้บอกว่า:

  • พารามิเตอร์fต้องมีฟังก์ชั่นจากชนิดโดยพลบางชนิดเดียวกันtt
  • fixเป็นฟังก์ชั่นที่ได้รับพารามิเตอร์ของชนิดและผลตอบแทนที่เป็นผลมาจากประเภทt -> tt

4
เพิ่มเติมว่า Haskell สามารถบอกได้ว่าx, y, zจะเหมือนกันNumประเภท eric แต่พวกเขายังคงสามารถIntegers, Doubles, Ratio Integers ... Haskell ยินดีที่จะให้เป็นตัวเลือกโดยพลระหว่างชนิดของตัวเลข แต่ไม่ได้สำหรับ typeclasses อื่น ๆ
John Dvorak

7

การอนุมานประเภทใน Go นั้นมี จำกัด มากและง่ายมาก ใช้งานได้ในโครงสร้างภาษาเดียว (การประกาศตัวแปร) และใช้ประเภทของด้านขวาและใช้เป็นประเภทสำหรับตัวแปรทางด้านซ้าย

การอนุมานประเภทใน Haskell สามารถใช้ได้ทุกที่มันสามารถใช้เพื่อสรุปประเภทของโปรแกรมทั้งหมด มันขึ้นอยู่กับการรวมซึ่งหมายความว่า (แนวคิด) ทุกประเภทจะอนุมาน "ทันที" และพวกเขาสามารถมีอิทธิพลซึ่งกันและกัน: ใน Go ข้อมูลประเภทสามารถไหลจากด้านขวามือของการประกาศตัวแปรไปทางซ้าย - ด้านมือไม่เคยไปในทิศทางอื่นและไม่เคยอยู่นอกการประกาศตัวแปร ใน Haskell ให้พิมพ์ข้อมูลได้อย่างอิสระในทุกทิศทางผ่านทางโปรแกรมทั้งหมด

อย่างไรก็ตามระบบประเภทของ Haskell นั้นทรงพลังมากจนการอนุมานประเภทนั้นล้มเหลวในการอนุมานประเภท (หรือแม่นยำยิ่งขึ้น: ต้องมีข้อ จำกัด เพื่อให้สามารถอนุมานประเภทได้เสมอ) ระบบประเภทของ Go นั้นง่ายมาก (ไม่มีการพิมพ์ย่อยไม่มีความหลากหลายแบบพารามิเตอร์) และการอนุมานจึง จำกัด ว่ามันจะประสบความสำเร็จเสมอ


4
"ใน Haskell การพิมพ์ข้อมูลจะไหลอย่างอิสระในทุกทิศทางผ่านโปรแกรมทั้งหมด": ฉันพบว่านี่เป็นสัญชาตญาณที่ดีมาก +1
Giorgio

การอ้างว่าคำตอบนี้ทำให้ในย่อหน้าสุดท้ายเป็นความเข้าใจผิดเล็กน้อย Haskell ไม่มีประเภทย่อย ยิ่งกว่านั้น parametric polymorphism ไม่ก่อให้เกิดปัญหาใด ๆ สำหรับความสมบูรณ์ของการอนุมานประเภท: Hindley-Milner บนแคลคูลัสแลมบ์ดา polymorphic ที่พบได้ทั่วไปที่สุด Haskell สามารถล้มเหลวในการอนุมานประเภท แต่จะอยู่ในคุณสมบัติของระบบที่ซับซ้อนเช่น GADT ที่เมื่อสูตรไร้เดียงสาไม่มีหลัก (เช่น "ตัวเลือกที่ดีที่สุด") ที่มีอยู่
Edward Z. Yang
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.