polymorphism ระดับสูงกว่าประเภทที่ไม่มีกล่อง


10

ฉันมีภาษาที่ไม่มีประเภทกล่องโดยค่าเริ่มต้นด้วยการอนุมานประเภทตาม Hindley – Milner ฉันต้องการเพิ่ม polymorphism ที่มีอันดับสูงกว่าโดยเฉพาะอย่างยิ่งสำหรับการทำงานกับประเภทที่มีอยู่

ฉันคิดว่าฉันเข้าใจวิธีตรวจสอบประเภทเหล่านี้ แต่ฉันไม่แน่ใจว่าต้องทำอย่างไรเมื่อรวบรวม ขณะนี้ฉันรวบรวมคำจำกัดความ polymorphic โดยการสร้างความเชี่ยวชาญเช่นเทมเพลต C ++ เพื่อให้สามารถทำงานกับค่าที่ไม่ได้ทำกล่อง เช่นให้คำจำกัดความของf<T>หากโปรแกรมเรียกใช้เท่านั้นf<Int32>และf<Char>จากนั้นเฉพาะความเชี่ยวชาญเหล่านั้นจะปรากฏในโปรแกรมรวบรวม (ตอนนี้ฉันกำลังรวบรวมโปรแกรมทั้งหมดไว้)

แต่เมื่อผ่านฟังก์ชั่น polymorphic เป็นอาร์กิวเมนต์ฉันไม่เห็นว่าฉันสามารถสร้างความเชี่ยวชาญเฉพาะทางแบบสแตติกได้เนื่องจากฟังก์ชั่นสามารถเลือกได้ที่รันไทม์ ฉันไม่มีทางเลือกนอกจากใช้การแสดงแบบกล่องหรือไม่? หรือมีวิธีแก้ไขปัญหาหรือไม่

ความคิดแรกของฉันคือการเข้ารหัสอย่างใด rank- n polymorphism เป็นอันดับ 1 แต่ผมไม่เชื่อว่ามันเป็นไปได้ในทั่วไปเพราะสูตรในตรรกะที่สร้างสรรค์ไม่จำเป็นต้องมี prenex แบบปกติ


อีกทางเลือกหนึ่งคือการลดปริมาณของมวยที่จำเป็นโดยการจัดเก็บบิตแมปซึ่งข้อโต้แย้งของฟังก์ชั่นและคำในหน่วยความจำเป็นพอยน์เตอร์ จากนั้นฟังก์ชั่น / โครงสร้าง polymorphic จะเป็น polymorphic จริง ๆ เหนือตัวชี้หรือคำที่กำหนดเองของข้อมูลและ structs สามารถเก็บฟิลด์สุดท้ายของพวกเขา (แม้ว่าจะเป็น polymorphic) แบบอินไลน์ บิตแมปเหล่านั้นยังสามารถใช้งานโดย GC เพื่อหลีกเลี่ยงความจำเป็นในการใช้ tagwords สำหรับประเภทที่ไม่ใช่ผลรวม
fread2281

@ fread2281: จริง ๆ แล้วฉันเคยทำสิ่งนี้ในภาษาที่เก่ากว่า ขณะนี้ฉันไม่ได้สร้างแท็กสำหรับประเภทที่ไม่รวมและไม่มี GC ฉันคิดว่ามันเข้ากันได้กับแนวทางของ Neel K เช่นกัน
Jon Purdy

คำตอบ:


6

ฉันคิดเล็กน้อยเกี่ยวกับเรื่องนี้ ปัญหาหลักคือโดยทั่วไปแล้วเราไม่รู้ว่าค่าของประเภท polymorphic นั้นใหญ่เพียงใด หากคุณไม่มีข้อมูลนี้คุณจะต้องได้รับข้อมูลอย่างใด Monomorphisation ได้รับข้อมูลนี้จากคุณโดยผู้เชี่ยวชาญด้าน polymorphism Boxing ได้รับข้อมูลนี้มาให้คุณโดยใส่ทุกอย่างลงไปในขนาดที่เป็นที่รู้จัก

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

Kindsκ::=nType constructorsA::=a:κ.A|α|A×B|A+B|AB|refA|Pad(k)|μα:κ.A

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

กฎการแบ่งให้ภาษาอังกฤษเป็นคณิตศาสตร์และควรมีลักษณะดังนี้:

α:nΓΓα:nΓ,α:nA:mΓα:n.A:m
ΓA:nΓB:mΓA×B:n+mΓA:nΓB:nΓA+B:n+1
ΓA:mΓB:nΓAB:1ΓA:nΓrefA:1
ΓPad(k):kΓ,α:nA:nΓμα:n.A:n

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

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

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

μα:1.ref(Pad(2)+int×α)

ดังนั้นสิ่งนี้ชี้ไปที่ค่ารายการว่างหรือคู่ของ int และตัวชี้ไปยังรายการที่เชื่อมโยงอื่น

การตรวจสอบประเภทของระบบเช่นนี้ก็ไม่ยากเช่นกัน อัลกอริทึมในกระดาษ ICFP ของฉันกับ Joshua Dunfield การตรวจสอบประเภทการพิมพ์สองทิศทางที่สมบูรณ์และใช้งานง่ายสำหรับ Polymorphism อันดับสูงใช้กับกรณีนี้โดยแทบไม่มีการเปลี่ยนแปลง


เยี่ยมฉันคิดว่านี่ครอบคลุมกรณีการใช้งานของฉันอย่างเรียบร้อย ฉันตระหนักถึงการใช้เหตุผลในการแสดงค่า (เช่น GHC *เทียบกับ#) แต่ก็ไม่ได้คิดที่จะทำแบบนี้ ดูเหมือนว่ามีเหตุผลที่จะ จำกัด ปริมาณการจัดอันดับที่สูงกว่าให้เป็นขนาดที่รู้จักและฉันคิดว่าสิ่งนี้จะทำให้ฉันสามารถสร้างความเชี่ยวชาญต่อขนาดแบบคงที่โดยไม่จำเป็นต้องรู้ประเภทจริง ตอนนี้ถึงเวลาอ่านบทความนั้นอีกครั้ง :)
Jon Purdy

1

สิ่งนี้ดูเหมือนจะใกล้เคียงกับปัญหาการรวบรวมมากกว่าปัญหา "วิทยาศาสตร์คอมพิวเตอร์เชิงทฤษฎี" ดังนั้นคุณน่าจะดีกว่าถ้าถามที่อื่น

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

เช่นการแสดงระดับต่ำของอาร์กิวเมนต์ที่ไม่มีกล่องสามารถแบ่งได้เป็นทางเลือกน้อยมากเช่นจำนวนเต็มหรือคล้ายกันทศนิยมหรือตัวชี้ ดังนั้นสำหรับฟังก์ชั่นf<T>บางทีคุณอาจต้องสร้างแอพพลิเคชั่นที่แตกต่างกัน 3 กล่องเท่านั้นและคุณสามารถแสดงโพลีมอร์ฟิคหนึ่งให้เป็น tuple ของทั้ง 3 ฟังก์ชั่นดังนั้นอินสแตนซ์ T to Int32 เพียงแค่เลือกองค์ประกอบแรกของ tuple ...


ขอบคุณสำหรับความช่วยเหลือของคุณ. ฉันไม่แน่ใจว่าจะถามที่ไหนเพราะผู้แปลครอบคลุมตั้งแต่ทฤษฎีระดับสูงไปจนถึงวิศวกรรมระดับต่ำ แต่ฉันคิดว่าผู้คนรอบ ๆ ที่นี่จะมีความคิดบางอย่าง ดูเหมือนว่ามวยอาจเป็นแนวทางที่ยืดหยุ่นที่สุดได้ที่นี่ หลังจากอ่านคำตอบและคิดถึงมันมากขึ้นแล้วทางออกที่สมเหตุสมผลเพียงข้อเดียวที่ฉันสามารถทำได้คือให้ความยืดหยุ่นบางอย่างและต้องการให้อาร์กิวเมนต์แบบ polymorphic รู้จักแบบคงที่เช่นผ่านตัวพิมพ์พารามิเตอร์เอง มันเป็นการแลกเปลี่ยนกันตลอดทาง : P
Jon Purdy

4
คำถามของ OP ประกอบด้วยปัญหา TCS ที่ถูกต้องสมบูรณ์เช่นวิธีอนุมานประเภทเมื่อ Damas-Hindley-Milner ขยายออกไปด้วยประเภทอันดับที่สูงขึ้น โดยทั่วไปอันดับ 2 polymorphism มีการอนุมานแบบ decidable แต่สำหรับการจัดอันดับ k> 2 การอนุมานแบบ type นั้นไม่สามารถตัดสินใจได้ Damas-Hindley-Milner จะเปลี่ยนแปลงสิ่งนี้หรือไม่ฉันไม่รู้ ในที่สุดทุกอย่างเกี่ยวกับคอมไพเลอร์สมัยใหม่ควรเป็นส่วนหนึ่งของ TCS แต่โดยทั่วไปแล้วไม่ใช่เพราะผู้รวบรวมคอมไพเลอร์อยู่ข้างหน้าของนักทฤษฎี
Martin Berger
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.