ระบบประเภท Haskell เป็นทางการเทียบเท่ากับ Java หรือไม่? [ปิด]


66

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


4
ฉันก็อยากรู้อยากเห็นว่านักทฤษฎีหมวดที่ยืดยาวตอบคำถามนี้; แม้ว่าฉันสงสัยว่าฉันจะเข้าใจเป็นพิเศษ แต่ฉันก็ยังสนใจในรายละเอียดของสิ่งนี้ ความโน้มเอียงของฉันจากสิ่งที่ผมเคยอ่านคือการที่ระบบการพิมพ์ HM ช่วยให้คอมไพเลอร์ที่จะรู้ตันเกี่ยวกับสิ่งที่รหัสของคุณไม่ซึ่งเป็นเหตุผลที่มันเป็นความสามารถในการอนุมานชนิดมากเช่นเดียวกับการให้การค้ำประกันจำนวนมากเกี่ยวกับพฤติกรรม แต่นั่นเป็นเพียงสัญชาตญาณของฉันและฉันแน่ใจว่ามีสิ่งอื่น ๆ ที่ฉันไม่รู้อย่างเต็มที่
Jimmy Hoffa

1
นี่เป็นคำถามที่ยอดเยี่ยม - ถึงเวลาทวีตกับผู้ติดตามเพื่อการอภิปรายที่ยอดเยี่ยมของ Haskell / JVM!
Martijn Verburg

6
@ m3th0dman: Scala รองรับฟังก์ชั่นการสั่งซื้อที่สูงกว่าเช่นเดียวกับ Java ใน Scala ฟังก์ชันระดับเฟิร์สคลาสจะถูกแสดงอย่างง่าย ๆ เป็นอินสแตนซ์ของคลาส abstract ด้วยวิธี abstract แบบเดียวเช่น Java แน่นอนว่าสกาล่ามีน้ำตาลเชิงประโยคสำหรับกำหนดฟังก์ชั่นเหล่านี้และมีห้องสมุดมาตรฐานที่หลากหลายทั้งประเภทฟังก์ชันที่กำหนดไว้ล่วงหน้าและวิธีการที่ยอมรับฟังก์ชั่น แต่จากมุมมองระบบประเภทซึ่งเป็นสิ่งที่คำถามนี้ไม่มีความแตกต่าง . ดังนั้นถ้า Scala สามารถทำได้ Java ก็สามารถทำได้เช่นกันและในความเป็นจริงก็มีไลบรารี FP ที่ได้รับแรงบันดาลใจจาก Haskell สำหรับ Java
Jörg W Mittag

2
@ m3th0dman: นั่นไม่ใช่สิ่งที่คำถามนี้เกี่ยวกับ
ฟิล

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

คำตอบ:


63

("Java" ตามที่ใช้ที่นี่ถูกกำหนดเป็นมาตรฐาน Java SE 7 ; "Haskell" ตามที่ใช้ที่นี่ถูกกำหนดเป็นHaskell 2010 มาตรฐาน )

สิ่งที่ชนิดของระบบ Java มี แต่ Haskell ไม่ได้:

  • polymorphism ชนิดย่อยเล็กน้อย
  • ข้อมูลประเภทรันไทม์บางส่วน

สิ่งที่ระบบประเภทของ Haskell มี แต่ Java นั้นไม่มี:

  • ad-hoc polymorphism ที่ จำกัด
    • ก่อให้เกิดความหลากหลายย่อย "ตามข้อ จำกัด "
  • ตัวแปรความแปรปรวนของตัวแปรที่สูงกว่า
  • การพิมพ์หลัก

แก้ไข:

ตัวอย่างของแต่ละจุดที่กล่าวข้างต้น:

เป็นเอกลักษณ์ของ Java (เมื่อเทียบกับ Haskell)

polymorphism ชนิดย่อยที่กำหนด

/* declare explicit subtypes (limited multiple inheritance is allowed) */
abstract class MyList extends AbstractList<String> implements RandomAccess {

    /* specify a type's additional initialization requirements */
    public MyList(elem1: String) {
        super() /* explicit call to a supertype's implementation */
        this.add(elem1) /* might be overridden in a subtype of this type */
    }

}

/* use a type as one of its supertypes (implicit upcasting) */
List<String> l = new ArrayList<>() /* some inference is available for generics */

ข้อมูลชนิดรันไทม์บางส่วน

/* find the outermost actual type of a value at runtime */
Class<?> c = l.getClass // will be 'java.util.ArrayList'

/* query the relationship between runtime and compile-time types */
Boolean b = l instanceOf MyList // will be 'false'

เป็นเอกลักษณ์ของ Haskell (เมื่อเทียบกับ Java)

polymorphism แบบเฉพาะกิจที่ถูกผูกไว้

-- declare a parametrized bound
class A t where
  -- provide a function via this bound
  tInt :: t Int
  -- require other bounds within the functions provided by this bound
  mtInt :: Monad m => m (t Int)
  mtInt = return tInt -- define bound-provided functions via other bound-provided functions

-- fullfill a bound
instance A Maybe where
  tInt = Just 5
  mtInt = return Nothing -- override defaults

-- require exactly the bounds you need (ideally)
tString :: (Functor t, A t) => t String
tString = fmap show tInt -- use bounds that are implied by a concrete type (e.g., "Show Int")

"ข้อ จำกัด ที่หลากหลาย" หลากหลายประเภท (ขึ้นอยู่กับความหลากหลายโฆษณาเฉพาะกิจ)

-- declare that a bound implies other bounds (introduce a subbound)
class (A t, Applicative t) => B t where -- bounds don't have to provide functions

-- use multiple bounds (intersection types in the context, union types in the full type)
mtString :: (Monad m, B t) => m (t String)
mtString = return mtInt -- use a bound that is implied by another bound (implicit upcasting)

optString :: Maybe String
optString = join mtString -- full types are contravariant in their contexts

ตัวแปรความแปรปรวนของตัวแปรที่สูงกว่า

-- parametrize types over type variables that are themselves parametrized
data OneOrTwoTs t x = OneVariableT (t x) | TwoFixedTs (t Int) (t String)

-- bounds can be higher-kinded, too
class MonadStrip s where
  -- use arbitrarily nested higher-kinded type variables
  strip :: (Monad m, MonadTrans t) => s t m a -> t m a -> m a

อาจารย์ใหญ่พิมพ์

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


7
อย่าใช้lเป็นตัวแปรตัวอักษรเดียวมันยากมากที่จะแยกความแตกต่าง1!
recursion.ninja

5
อาจเป็นเรื่องที่น่าสังเกตว่าแม้ว่าคุณจะถูกต้องอย่างแน่นอนที่ Java มีข้อมูลประเภทรันไทม์บางอย่างและ Haskell ไม่ได้คุณสามารถใช้ Typeable class-class ใน Haskell เพื่อให้สิ่งที่มีลักษณะเหมือนข้อมูลประเภทรันไทม์สำหรับหลายประเภท (พร้อม PolyKinded รุ่นใหม่กว่า เรียนในทางมันจะเป็นทุกประเภท iirc) แม้ว่าฉันคิดว่ามันขึ้นอยู่กับสถานการณ์ว่าจริง ๆ แล้วมันผ่านข้อมูลชนิดใด ๆ ที่รันไทม์หรือไม่

3
@DarkOtter ฉันรู้Typeableแต่ Haskell 2010 ไม่ได้มี (อาจ Haskell 2014 จะ?)
Flame ของ Ptharien

5
ประเภทผลรวม (ปิด) เกี่ยวกับอะไร มันเป็นหนึ่งในกลไกสำคัญสำหรับการเข้ารหัสข้อ จำกัด
tibbe

3
Nullability? ความสมบูรณ์ (ไม่มีความแปรปรวนร่วม)? ปิดการจับคู่ประเภท / รูปแบบผลรวมหรือไม่ คำตอบนี้แคบเกินไป
Peaker

32

ระบบชนิดของ Java ขาดความแตกต่างของชนิดที่สูงกว่า; ระบบประเภทของ Haskell มีอยู่แล้ว

ในคำอื่น ๆ : ใน Java, ประเภทก่อสร้างสามารถนามธรรมมากกว่าประเภท แต่ไม่เกินประเภทก่อสร้างในขณะที่ใน Haskell, ประเภทก่อสร้างสามารถนามธรรมมากกว่าประเภทก่อสร้างเช่นเดียวกับประเภท

ในภาษาอังกฤษ: ใน Java ทั่วไปไม่สามารถใช้ประเภทสามัญอื่นและกำหนดพารามิเตอร์ได้

public void <Foo> nonsense(Foo<Integer> i, Foo<String> j)

ในขณะที่ใน Haskell นี้ค่อนข้างง่าย

higherKinded :: Functor f => f Int -> f String
higherKinded = fmap show

28
โปรดลองอีกครั้งเป็นภาษาอังกฤษใช่ไหม : P
Mason Wheeler

8
@ Matt: ตัวอย่างเช่นฉันไม่สามารถเขียนใน Java แต่ฉันสามารถเขียนเทียบเท่าใน Haskell <T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings)นี้: ความคิดที่นี่จะเป็นว่าถ้ามีคนเรียกมันว่าconvertStringsToInts<ArrayList>มันจะใช้รายการของสตริงและส่งกลับรายการของจำนวนเต็ม และถ้าพวกเขาใช้convertStringsToInts<LinkedList>มันจะเหมือนกับรายการที่ลิงก์แทน
sepp2k

8
พหุสัณฐานที่สูงกว่านี้ไม่ใช่แบบนี้มากกว่าอันดับที่ 1 กับ n หรือไม่?
อดัม

8
@ JörgWMittag: ความเข้าใจของฉันคือความหลากหลายในระดับสูงที่เกี่ยวข้องกับforallประเภทของคุณ ใน Haskell ประเภทคือโดยปริยายa -> b forall a. forall b. a -> bด้วยส่วนขยายคุณสามารถทำให้สิ่งเหล่านี้forallชัดเจนและย้ายไปมาได้
Tikhon Jelvis

8
@ อดัมมีความเข้มงวด: อันดับที่สูงขึ้นและประเภทที่สูงขึ้นจะแตกต่างกันโดยสิ้นเชิง GHC ยังสามารถจัดอันดับประเภทที่สูงกว่า (เช่นประเภท forall) ด้วยส่วนขยายภาษาบางอย่าง Java รู้ชนิดที่ดีกว่าหรืออันดับสูงกว่าไม่ทราบ
Ingo

11

เพื่อเติมเต็มคำตอบอื่น ๆ ระบบประเภทของ Haskell ไม่มีการพิมพ์ย่อยในขณะที่พิมพ์ภาษาเชิงวัตถุเป็นภาษาจาวา

ในทฤษฎีการเขียนโปรแกรมภาษา , subtyping (ยังเป็นชนิดย่อย polymorphismหรือรวม polymorphism ) เป็นรูปแบบของประเภทแตกต่างซึ่งเป็นชนิดย่อยเป็นประเภทข้อมูลที่เกี่ยวข้องกับประเภทข้อมูลอื่น (คนsupertype ) โดยความคิดของบางอย่างทดแทนหมายความว่าองค์ประกอบของโปรแกรมโดยทั่วไปซับรูทีน หรือฟังก์ชั่นที่เขียนขึ้นเพื่อใช้งานในองค์ประกอบของ supertype ยังสามารถทำงานกับองค์ประกอบของ subtype ถ้า S เป็นประเภทย่อยของ T ความสัมพันธ์ของการพิมพ์ย่อยนั้นมักจะเขียน S <: T ซึ่งหมายความว่าคำใด ๆ ของประเภท S สามารถนำไปใช้อย่างปลอดภัยในบริบทที่คาดว่าจะมีคำศัพท์ประเภท T ความหมายที่แม่นยำของการพิมพ์ย่อยอย่างมีนัยสำคัญขึ้นอยู่กับรายละเอียดของสิ่งที่ "ใช้อย่างปลอดภัยในบริบทที่" หมายถึงในภาษาการเขียนโปรแกรมที่กำหนด ระบบการพิมพ์ของภาษาการเขียนโปรแกรมเป็นหลักกำหนดความสัมพันธ์ subtyping ของตัวเองซึ่งอาจจะดีจิ๊บจ๊อย

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


4
แม้ว่านั่นไม่ได้หมายความว่าคุณจะไม่ได้รับ ad-hoc polymorphism คุณทำในรูปแบบที่แตกต่างกัน (พิมพ์คลาสแทนประเภทย่อยที่หลากหลาย)

3
การแบ่งคลาสย่อยไม่ใช่การพิมพ์ย่อย!
Frank Shearar

8

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

อีกอย่างที่คนเราไม่พูดถึงก็คือชนิดข้อมูลพีชคณิต นั่นคือความสามารถในการสร้างประเภทจากผลรวม ('หรือ') และผลิตภัณฑ์ ('และ') ประเภทอื่น ๆ คลาส Java ทำผลิตภัณฑ์ (ฟิลด์ a และฟิลด์ b, พูด) ได้ดี แต่พวกเขาไม่ได้ผลรวม (ฟิลด์ a หรือฟิลด์ b, พูด) Scala ต้องเข้ารหัสสิ่งนี้เป็นคลาสของเคสจำนวนมากซึ่งไม่เหมือนกัน และในขณะที่มันใช้งานได้กับ Scala มันค่อนข้างยืดยาวที่จะบอกว่า Java มี

Haskell ยังสามารถสร้างประเภทฟังก์ชั่นโดยใช้ตัวสร้างฟังก์ชั่น -> ในขณะที่วิธีการของ Java มีลายเซ็นประเภทคุณไม่สามารถรวมได้

ระบบชนิดของ Java เปิดใช้งานโมดูลาร์ประเภทที่ Haskell ไม่ได้รับ ก่อนที่จะมี OSGi สำหรับ Haskell


1
@ MattFenwick ฉันแก้ไขย่อหน้าที่ 3 ตามความคิดเห็นของคุณ ระบบทั้งสองประเภททำหน้าที่ต่างกันมาก
GarethR

ฉันจะไม่เรียกคุณสมบัติของระบบประเภท ADT คุณสามารถจำลอง (ถ้าอย่างเชื่องช้า) โดยใช้ OO wrappers
leftaroundabout

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

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