เหตุผลใดที่ scala ไม่รองรับประเภทที่อ้างอิงอย่างชัดเจน?


109

มีประเภทที่ขึ้นอยู่กับเส้นทางและฉันคิดว่ามันเป็นไปได้ที่จะแสดงคุณลักษณะเกือบทั้งหมดของภาษาเช่น Epigram หรือ Agda ใน Scala แต่ฉันสงสัยว่าทำไม Scala ไม่สนับสนุนสิ่งนี้อย่างชัดเจนมากขึ้นเหมือนกับที่ทำในด้านอื่น ๆ (พูด , DSLs)? อะไรที่ฉันขาดหายไปเช่น "มันไม่จำเป็น"?


3
นักออกแบบของ Scala เชื่อว่า Barendregt Lambda Cube ไม่ใช่ทฤษฎีประเภทที่สมบูรณ์แบบ นั่นอาจจะใช่หรือไม่ใช่เหตุผล
Jörg W Mittag

8
@ JörgWMittag Lamda Cube คืออะไร? อุปกรณ์มายากลบางประเภท?
เถ้าแก่คห. Nazary

@ ashy_32bit ดูบทความ "Introduction to Generalized Type Systems" ของ Barendregt ที่นี่: diku.dk/hjemmesider/ansatte/henglein/papers/barendregt1991.pdf
iainmcgin

คำตอบ:


152

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

การสนับสนุนที่แท้จริง Scala สำหรับประเภทการขึ้นผ่านทางประเภทขึ้นอยู่กับเส้นทาง สิ่งเหล่านี้อนุญาตให้ประเภทขึ้นอยู่กับเส้นทางตัวเลือกผ่านกราฟวัตถุ - (เช่นค่า -) เช่นนั้น

scala> class Foo { class Bar }
defined class Foo

scala> val foo1 = new Foo
foo1: Foo = Foo@24bc0658

scala> val foo2 = new Foo
foo2: Foo = Foo@6f7f757

scala> implicitly[foo1.Bar =:= foo1.Bar] // OK: equal types
res0: =:=[foo1.Bar,foo1.Bar] = <function1>

scala> implicitly[foo1.Bar =:= foo2.Bar] // Not OK: unequal types
<console>:11: error: Cannot prove that foo1.Bar =:= foo2.Bar.
              implicitly[foo1.Bar =:= foo2.Bar]

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

อย่างไรก็ตามมักจะถูกคัดค้านว่า Scala ไม่ใช่ภาษาประเภทที่อ้างอิงแบบ "เต็ม" เนื่องจากไม่มีผลรวมและประเภทผลิตภัณฑ์ตามที่พบใน Agda หรือ Coq หรือ Idris เป็นเนื้อแท้ ฉันคิดว่าสิ่งนี้สะท้อนให้เห็นถึงการตรึงรูปแบบมากกว่าปัจจัยพื้นฐานในระดับหนึ่งอย่างไรก็ตามฉันจะพยายามแสดงให้เห็นว่า Scala ใกล้เคียงกับภาษาอื่น ๆ เหล่านี้มากกว่าที่รับทราบโดยทั่วไป

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

scala> trait Sigma {
     |   val foo: Foo
     |   val bar: foo.Bar
     | }
defined trait Sigma

scala> val sigma = new Sigma {
     |   val foo = foo1
     |   val bar = new foo.Bar
     | }
sigma: java.lang.Object with Sigma{val bar: this.foo.Bar} = $anon$1@e3fabd8

และในความเป็นจริงนี่เป็นส่วนสำคัญของการเข้ารหัสประเภทวิธีการที่ต้องพึ่งพาซึ่งจำเป็นสำหรับการหลีกหนีจาก 'Bakery of Doom'ใน Scala ก่อน 2.10 (หรือก่อนหน้านี้ผ่านตัวเลือกคอมไพเลอร์ Scala -Ydependent-method type)

ประเภทผลิตภัณฑ์ที่ขึ้นอยู่กับ (หรือที่เรียกว่าประเภท Pi) เป็นฟังก์ชันจากค่าเป็นประเภท สิ่งเหล่านี้เป็นกุญแจสำคัญในการแสดงเวกเตอร์ขนาดคงที่และลูกโปสเตอร์อื่น ๆ สำหรับภาษาโปรแกรมที่พิมพ์ขึ้น เราสามารถเข้ารหัสประเภท Pi ใน Scala โดยใช้การรวมกันของประเภทที่ขึ้นกับพา ธ ประเภทซิงเกิลตันและพารามิเตอร์นัย อันดับแรกเรากำหนดลักษณะที่จะแสดงฟังก์ชันจากค่าของประเภท T ถึงประเภท U

scala> trait Pi[T] { type U }
defined trait Pi

เราสามารถกำหนดวิธีการหลายรูปแบบที่ใช้ประเภทนี้ได้

scala> def depList[T](t: T)(implicit pi: Pi[T]): List[pi.U] = Nil
depList: [T](t: T)(implicit pi: Pi[T])List[pi.U]

(สังเกตการใช้ประเภทที่ขึ้นกับพา ธpi.Uในประเภทผลลัพธ์List[pi.U]) เมื่อระบุค่าประเภท T ฟังก์ชันนี้จะส่งกลับรายการค่า (n ว่าง) ของประเภทที่ตรงกับค่า T นั้น ๆ

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

scala> object Foo
defined module Foo

scala> object Bar
defined module Bar

scala> implicit val fooInt = new Pi[Foo.type] { type U = Int }
fooInt: java.lang.Object with Pi[Foo.type]{type U = Int} = $anon$1@60681a11

scala> implicit val barString = new Pi[Bar.type] { type U = String }
barString: java.lang.Object with Pi[Bar.type]{type U = String} = $anon$1@187602ae

และตอนนี้นี่คือฟังก์ชันการใช้งานประเภท Pi ของเรา

scala> depList(Foo)
res2: List[fooInt.U] = List()

scala> depList(Bar)
res3: List[barString.U] = List()

scala> implicitly[res2.type <:< List[Int]]
res4: <:<[res2.type,List[Int]] = <function1>

scala> implicitly[res2.type <:< List[String]]
<console>:19: error: Cannot prove that res2.type <:< List[String].
              implicitly[res2.type <:< List[String]]
                    ^

scala> implicitly[res3.type <:< List[String]]
res6: <:<[res3.type,List[String]] = <function1>

scala> implicitly[res3.type <:< List[Int]]
<console>:19: error: Cannot prove that res3.type <:< List[Int].
              implicitly[res3.type <:< List[Int]]

(โปรดทราบว่าที่นี่เราใช้<:<ตัวดำเนินการพยานประเภทย่อยของ Scala มากกว่า=:=เพราะres2.typeและres3.typeเป็นประเภทซิงเกิลตันและด้วยเหตุนี้จึงแม่นยำกว่าประเภทที่เรากำลังตรวจสอบใน RHS)

อย่างไรก็ตามในทางปฏิบัติใน Scala เราจะไม่เริ่มต้นด้วยการเข้ารหัสประเภท Sigma และ Pi แล้วดำเนินการต่อจากที่นั่นเหมือนที่เราทำใน Agda หรือ Idris แต่เราจะใช้ประเภทที่ขึ้นกับพา ธ ประเภทซิงเกิลตันและนัยโดยตรง คุณสามารถค้นหาตัวอย่างมากมายของวิธีนี้เล่นออกมาในไม่มีรูปแบบ: ชนิดขนาด , บันทึกขยาย , HLists ครอบคลุม , เศษเหล็กสำเร็จรูปของคุณ , ทั่วไปซิปฯลฯ เป็นต้น

การคัดค้านที่เหลืออยู่เพียงอย่างเดียวที่ฉันเห็นคือในการเข้ารหัสประเภท Pi ข้างต้นเราต้องการให้ประเภทซิงเกิลตันของค่าที่ขึ้นอยู่กับการแสดงออก น่าเสียดายใน Scala สิ่งนี้เป็นไปได้สำหรับค่าของประเภทการอ้างอิงเท่านั้นไม่ใช่สำหรับค่าของประเภทที่ไม่อ้างอิง (esp. เช่น int) นี้เป็นความอัปยศ แต่ไม่ได้เป็นความยากลำบากที่แท้จริง: ตรวจสอบประเภทของ Scala หมายถึงประเภทเดี่ยวของค่าที่ไม่ใช่การอ้างอิงภายในและมีได้รับคู่ของการทดลองในการทำให้พวกเขาแสดงออกโดยตรง ในทางปฏิบัติเราสามารถหลีกเลี่ยงปัญหาที่มีการเข้ารหัสประเภทระดับมาตรฐานเป็นธรรมของจำนวนธรรมชาติ

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


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

8
ฉันลดคะแนนลงเพราะฉันไม่สามารถแยกแยะเทคนิคที่เป็นสาระสำคัญจากเทคนิคที่อธิบายไว้ใน " Faking It" ของMcBride citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.22.2636นั่นคือวิธีการจำลอง ประเภทที่ขึ้นกับไม่ได้ระบุไว้โดยตรง
sclv

2
@sclv ฉันคิดว่าคุณพลาดที่ Scala มีประเภทที่พึ่งพาโดยไม่มีรูปแบบการเข้ารหัสใด ๆ : ดูตัวอย่างแรกด้านบน คุณคิดถูกที่การเข้ารหัสประเภท Pi ของฉันใช้เทคนิคบางอย่างเช่นเดียวกับกระดาษของ Connor แต่มาจากวัสดุพิมพ์ที่มีประเภทที่ขึ้นกับพา ธ และประเภทซิงเกิลตันอยู่แล้ว
Miles Sabin

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

9
=: = ไม่ใช่ระดับค่าของสกาล่าเป็นตัวสร้างประเภท - ค่าสำหรับสิ่งนั้นอยู่ที่นี่: github.com/scala/scala/blob/v2.10.3/src/library/scala/…และดูเหมือนจะไม่ โดยเฉพาะอย่างยิ่งแตกต่างจากพยานในเรื่องความเท่าเทียมกันในภาษาที่พิมพ์ขึ้นเช่น Agda และ Idris: refl (ดูwww2.tcs.ifi.lmu.de/~abel/Equality.pdfตอนที่ 2 และeb.host.cs.st-andrews.ac.uk/writings/idris-tutorial.pdfหัวข้อ 8.1 ตามลำดับ)
pdxleif

6

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


คุณจะใจดีพอที่จะให้ความรู้พื้นฐานทางทฤษฎีเกี่ยวกับประเภทที่ขึ้นอยู่กับฉันได้หรือไม่ (อาจมีลิงค์)
เถ้าแก่คห. Nazary

3
@ ashy_32bit หากคุณสามารถเข้าถึง "หัวข้อขั้นสูงในประเภทและภาษาโปรแกรม" โดยเบนจามินเพียร์ซมีบทหนึ่งที่ให้คำแนะนำที่สมเหตุสมผลเกี่ยวกับประเภทที่อ้างอิง นอกจากนี้คุณยังสามารถอ่านบทความของ Conor McBride ซึ่งมีความสนใจเป็นพิเศษในประเภทที่ต้องพึ่งพาในทางปฏิบัติมากกว่าในทางทฤษฎี
iainmcgin

3

ฉันเชื่อว่าประเภทที่ขึ้นกับพา ธ ของ Scala สามารถแสดงได้เฉพาะΣ-types เท่านั้น แต่ไม่ใช่Π-types นี้:

trait Pi[T] { type U }

ไม่ใช่ประเภทΠ ตามความหมายΠ-type หรือผลิตภัณฑ์ที่ขึ้นต่อกันเป็นฟังก์ชันที่ประเภทผลลัพธ์ขึ้นอยู่กับค่าอาร์กิวเมนต์ซึ่งเป็นตัวแทนของตัวระบุปริมาณสากลเช่น∀x: A, B (x) อย่างไรก็ตามในกรณีข้างต้นขึ้นอยู่กับประเภท T เท่านั้น แต่ไม่ใช่ค่าบางค่าของประเภทนี้ Pi trait นั้นเป็น-type ตัวระบุอัตถิภาวนิยมเช่น iex: A, B (x) การอ้างอิงตัวเองของวัตถุในกรณีนี้จะทำหน้าที่เป็นตัวแปรเชิงปริมาณ อย่างไรก็ตามเมื่อส่งผ่านเป็นพารามิเตอร์โดยนัยมันจะลดเป็นฟังก์ชันประเภทธรรมดาเนื่องจากได้รับการแก้ไขแบบฉลาด การเข้ารหัสสำหรับผลิตภัณฑ์ที่เกี่ยวข้องใน Scala อาจมีลักษณะดังต่อไปนี้:

trait Sigma[T] {
  val x: T
  type U //can depend on x
}

// (t: T) => (∃ mapping(x, U), x == t) => (u: U); sadly, refinement won't compile
def pi[T](t: T)(implicit mapping: Sigma[T] { val x = t }): mapping.U 

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

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


1
Miles Sabin ด้านบนแสดงตัวอย่างการใช้Piเพื่อสร้างประเภทขึ้นอยู่กับค่า
missingfaktor

ในตัวอย่างdepListสารสกัดพิมพ์UจากPi[T]เลือกสำหรับประเภท (ไม่ได้ค่า) tของ ประเภทนี้เกิดขึ้นเป็นประเภทซิงเกิลตันซึ่งปัจจุบันมีอยู่ในออบเจ็กต์เดี่ยวของ Scala และแสดงค่าที่แน่นอน ตัวอย่างสร้างการนำไปใช้งานหนึ่งรายการPiต่อชนิดอ็อบเจ็กต์เดี่ยวดังนั้นการจับคู่ประเภทที่มีค่าในรูปแบบΣ ในทางกลับกันΠ-type เป็นสูตรที่ตรงกับโครงสร้างของพารามิเตอร์อินพุต อาจเป็นไปได้ว่า Scala ไม่มีเนื่องจากΠ-types กำหนดให้ทุกประเภทพารามิเตอร์เป็น GADT และ Scala จะไม่แยกความแตกต่างของ GADT จากประเภทอื่น ๆ
P. Frolov

โอเคฉันสับสนนิดหน่อย pi.Uในตัวอย่างของ Miles จะไม่นับเป็นประเภทที่อ้างอิงหรือไม่? piมันอยู่ในค่า
missingfaktor

2
แน่นอนว่ามันนับเป็นประเภทที่ขึ้นอยู่กับ แต่มีรสชาติที่แตกต่างกัน: Σ-type ("มี x เช่น P (x)", ตรรกะฉลาด) และΠ-type ("สำหรับ x ทั้งหมด, P (x)") . ในขณะที่คุณสังเกตประเภทขึ้นอยู่กับมูลค่าของpi.U piปัญหาในการป้องกันไม่ให้trait Pi[T]กลายเป็นΠ-type คือเราไม่สามารถทำให้มันขึ้นอยู่กับค่าของอาร์กิวเมนต์โดยพลการ (เช่นtในdepList) โดยไม่ต้องยกอาร์กิวเมนต์นั้นที่ระดับประเภท
P. Frolov

1

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

นี่ไม่ใช่ความพยายามที่จะตอบคำถามว่าการเปลี่ยน Scala ให้เป็นแบบ Idris นั้นง่ายเพียงใด (ฉันคิดว่ายากมาก) หรือเขียนไลบรารีที่ให้การสนับสนุนโดยตรงมากขึ้นสำหรับความสามารถเช่น Idris (เช่น singletonsพยายามที่จะอยู่ใน Haskell)

แต่ฉันต้องการเน้นความแตกต่างในทางปฏิบัติระหว่าง Scala กับภาษาเช่น Idris
อะไรคือรหัสบิตสำหรับนิพจน์ระดับค่าและประเภท? Idris ใช้รหัสเดียวกัน Scala ใช้รหัสที่แตกต่างกันมาก

Scala (คล้ายกับ Haskell) อาจเข้ารหัสการคำนวณระดับประเภทจำนวนมากได้ สิ่งนี้แสดงโดยไลบรารีเช่นshapeless. ห้องสมุดเหล่านี้ใช้เทคนิคที่น่าประทับใจและชาญฉลาด อย่างไรก็ตามรหัสระดับประเภทของพวกเขา (ในปัจจุบัน) ค่อนข้างแตกต่างจากนิพจน์ระดับค่า (ฉันพบว่าช่องว่างนั้นค่อนข้างใกล้กว่าใน Haskell) Idris อนุญาตให้ใช้นิพจน์ระดับค่าในระดับประเภท AS IS

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

พิจารณารหัสที่ได้รับการยืนยัน ดู:
https://github.com/idris-lang/Idris-dev/blob/v1.3.0/libs/contrib/Interfaces/Verified.idr
ตัวตรวจสอบประเภทตรวจสอบการพิสูจน์ของ monadic / functor / กฎการบังคับใช้และการพิสูจน์เป็นเรื่องจริง การใช้ monad / functor / applicative และไม่ใช่ระดับที่เข้ารหัสบางประเภทที่เทียบเท่าซึ่งอาจเหมือนหรือไม่เหมือนกัน คำถามใหญ่คือเรากำลังพิสูจน์อะไร?

ฉันสามารถทำได้เช่นเดียวกันโดยใช้เทคนิคการเข้ารหัสที่ชาญฉลาด (ดูต่อไปนี้สำหรับเวอร์ชัน Haskell ฉันไม่เคยเห็น Scala)
https://blog.jle.im/entry/verified-instances-in-haskell.html
https: // github.com/rpeszek/IdrisTddNotes/wiki/Play_FunctorLaws
ยกเว้นประเภทมีความซับซ้อนมากจนยากที่จะมองเห็นกฎหมายนิพจน์ระดับค่าจะถูกแปลง (โดยอัตโนมัติ แต่ยังคงอยู่) เพื่อพิมพ์ระดับสิ่งต่างๆและคุณต้องเชื่อถือการแปลงนั้นด้วย . มีช่องว่างสำหรับข้อผิดพลาดในทั้งหมดนี้ซึ่งเป็นการท้าทายวัตถุประสงค์ของคอมไพเลอร์ที่ทำหน้าที่เป็นผู้ช่วยพิสูจน์

(แก้ไข 2018.8.10) เมื่อพูดถึงความช่วยเหลือในการพิสูจน์นี่คือความแตกต่างที่ยิ่งใหญ่อีกอย่างระหว่าง Idris และ Scala ไม่มีสิ่งใดใน Scala (หรือ Haskell) ที่สามารถป้องกันไม่ให้เขียนการพิสูจน์ที่แตกต่าง:

case class Void(underlying: Nothing) extends AnyVal //should be uninhabited
def impossible() : Void = impossible()

ในขณะที่ Idris มีtotalคำหลักที่ป้องกันไม่ให้โค้ดเช่นนี้รวบรวม

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

ฉันยังใหม่เกินไปสำหรับ Scala ที่จะตอบคำถามนั้นด้วยตัวเอง

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