ข้อ จำกัด ของประเภท Nat ในรูปแบบไม่มีรูปแบบ


151

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

การเป็นตัวแทนนี้มีความสามารถในการแสดงจำนวนมากเช่น1000000หรือ 2 53หรือสิ่งนี้จะทำให้คอมไพเลอร์สกาล่าจะยอมแพ้?


21
ไมล์สนำเสนอ NE Scalaปีที่ผ่านมาที่อยู่คำถามนี้และคำตอบสั้น ๆ ก็คือว่ามันจะเป็นไปได้ที่จะเป็นตัวแทนจำนวนมากในระดับประเภทใน Scala หรืออย่างน้อยที่สุดก็ใน 2.10 โดยใช้ประเภทเดี่ยวแต่มันอาจจะไม่คุ้มค่า ในปัจจุบันไม่มีรูปแบบ 2.0 ยังคงใช้การเข้ารหัสของคริสตจักรซึ่งคุณจะได้รับ 1,000 หรือมากกว่านั้นก่อนที่คอมไพเลอร์จะยอมแพ้
เทรวิสบราวน์

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

2
หากคุณต้องการคำนวณทางคณิตศาสตร์เกี่ยวกับตัวเลขระดับประเภทขนาดใหญ่คุณอาจพิจารณานำไปใช้เป็นรายการบิตที่เชื่อมโยง
Karol S

1
@ KarolS ฉันมีการใช้งานกลยุทธ์นั้น! และผมก็ยินดีที่จะมีส่วนร่วมในมันไม่มีรูปแบบถ้าใครสนใจแม้จะไร้ค่ามันเว้นแต่คนที่สามารถช่วยแก้stackoverflow.com/questions/31768203/...
beefyhalo

2
ดูเหมือนว่าstackoverflow.com/questions/31768203/…ได้รับการแก้ไขแล้วดังนั้นคุณสามารถให้รหัสและปิดคำถามด้วยคำตอบของคุณเองได้หรือไม่?
Andriy Kuba

คำตอบ:


17

ฉันจะลองด้วยตัวเอง ฉันยินดีที่จะยอมรับคำตอบที่ดีกว่าจาก Travis Brown หรือ Miles Sabin

ปัจจุบันไม่สามารถใช้Nat แทนจำนวนมากได้

ในการใช้งาน Nat ในปัจจุบันค่าจะสอดคล้องกับจำนวนของ shapeless ที่ซ้อนกันประเภท [cc]:

scala> Nat(3)
res10: shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]] = Succ()

ดังนั้นเพื่อเป็นตัวแทนของจำนวน 1000000 คุณจะต้องมีประเภทที่ซ้อนกัน 1000000 ระดับลึกซึ่งแน่นอนจะรวบรวมคอมไพเลอร์สกาล่า ขีด จำกัด ปัจจุบันดูเหมือนจะอยู่ที่ประมาณ 400 จากการทดลอง แต่สำหรับการรวบรวมที่สมเหตุสมผลมันอาจจะดีที่สุดที่จะอยู่ต่ำกว่า 50

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

scala> type OneMillion = Witness.`1000000`.T
defined type alias OneMillion

scala> type AlsoOneMillion = Witness.`1000000`.T
defined type alias AlsoOneMillion

scala> type OneMillionAndOne = Witness.`1000001`.T
defined type alias OneMillionAndOne

scala> implicitly[OneMillion =:= AlsoOneMillion]
res0: =:=[OneMillion,AlsoOneMillion] = <function1>

scala> implicitly[OneMillion =:= OneMillionAndOne]
<console>:16: error: Cannot prove that OneMillion =:= OneMillionAndOne.
       implicitly[OneMillion =:= OneMillionAndOne]
                 ^

สิ่งนี้สามารถใช้เพื่อบังคับใช้ขนาดอาร์เรย์เดียวกันเมื่อทำการดำเนินการบิตบน Array [Byte]


เพิ่งเห็นคำตอบนี้และ +1 นี่เป็นตัวอย่างที่ดี เป็นที่น่าสังเกตว่าคุณสามารถให้คลาสของประเภทอย่างเช่น Shapeless ops.nat.Sumที่จะเป็นพยานว่าจำนวนเต็มระดับสองประเภทมีผลรวมเป็นพิเศษและอื่น ๆ (พวกมันจะต้องมีมาโครให้)
Travis Brown

1
นี่คือตัวอย่างของConcatคลาสชนิดที่อนุญาตให้เชื่อมสตริงสองระดับประเภทผ่านทางแมโคร คลาสประเภทสำหรับการรวมจำนวนเต็มระดับประเภทอาจจะดูคล้ายกันมาก
Frank S. Thomas

5

การNatเข้ารหัสของตัวเลขไม่มีรูปแบบที่ระดับประเภทโดยใช้การเข้ารหัสของโบสถ์ วิธีทางเลือกคือการเป็นตัวแทนของธรรมชาติเป็นระดับประเภท HList ของบิต

ตรวจสอบความหนาแน่นซึ่งดำเนินการแก้ปัญหานี้ในรูปแบบไม่มีรูปแบบ

ฉันไม่ได้ทำงานกับมันมาระยะหนึ่งแล้วและมันก็ต้องการการLazyขัดที่ไม่มีรูปทรง ' ที่นี่และเมื่อไรที่ scalac ยอมแพ้ แต่แนวคิดนั้นแข็งแกร่ง :)

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