การอนุมานประเภทด้วยประเภทผลิตภัณฑ์


15

ฉันกำลังทำงานกับคอมไพเลอร์สำหรับภาษาที่ต่อกันและต้องการเพิ่มการสนับสนุนการอนุมานประเภท ฉันเข้าใจ Hindley - Milner แต่ฉันได้เรียนรู้ทฤษฎีประเภทเมื่อฉันไปดังนั้นฉันไม่แน่ใจว่าจะปรับตัวอย่างไร ระบบต่อไปนี้เป็นระบบเสียงที่ดี

คำคือตัวอักษรองค์ประกอบของคำพูดคำพูดของคำหรือดั้งเดิม

e::=x|ee|[e]|

เงื่อนไขทั้งหมดแสดงถึงฟังก์ชั่น สำหรับสองฟังก์ชั่นและ ,นั่นคือ juxtaposition แสดงถึงการจัดองค์ประกอบย้อนกลับ ตัวอักษรหมายถึงฟังก์ชั่น niladice 2e1e2e1e2=e2e1

คำอื่น ๆ นอกเหนือจากการแต่งมีกฎประเภทพื้นฐาน:

x:ι[Lit]Γe:σΓ[e]:α.ασ×α[Quot],α not free in Γ

ไม่มีกฎระเบียบสำหรับการประยุกต์ใช้สะดุดตาเนื่องจากภาษาที่เรียงต่อกันขาด

ประเภทคือตัวอักษรตัวแปรประเภทหรือฟังก์ชั่นจากสแต็คไปสแต็คที่สแต็กจะถูกกำหนดเป็น tuple ที่ซ้อนกันขวา ฟังก์ชั่นทั้งหมดมีความหลากหลายโดยนัยเกี่ยวกับ "ส่วนที่เหลือของสแต็ค"

τ::=ι|α|ρρρ::=()|τ×ρσ::=τ|α.σ

นี่เป็นสิ่งแรกที่ดูเหมือนผู้ต้องสงสัย แต่ฉันไม่รู้แน่ชัดว่าเกิดอะไรขึ้นกับมัน

เพื่อช่วยให้สามารถอ่านและลดวงเล็บได้ฉันจะสมมติว่าในแบบแผนชุด ฉันจะใช้อักษรตัวใหญ่สำหรับตัวแปรที่แสดงถึงสแต็กแทนที่จะเป็นค่าเดียวab=b×(a)

มีหกดั้งเดิม ห้าคนแรกนั้นไม่น่ากลัวเลย dupใช้ค่าสูงสุดและสร้างสำเนาสองชุด swapเปลี่ยนลำดับของค่าสองอันดับแรก popทิ้งค่าบนสุด quoteรับค่าและสร้างใบเสนอราคา (ฟังก์ชัน) ที่ส่งคืน applyใช้ใบเสนอราคากับสแต็ก

dup::Ab.AbAbbswap::Abc.AbcAcbpop::Ab.AbAquote::Ab.AbA(C.CCb)apply::AB.A(AB)B

Combinator ที่ผ่านมาcomposeควรจะใช้เวลาสองใบเสนอราคาและผลตอบแทนประเภทของการเรียงต่อกันของพวกเขานั่นคือe_2] ในภาษาที่เรียงต่อกันแบบคงที่ประเภทของแมวนั้นตรงไปตรงมามาก[e1][e2]compose=[e1e2]compose

compose::ABCD.A(BC)(CD)A(BD)

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

compose::ABCDE.A(BC)(DE)A

หากคุณให้แสดงถึงความแตกต่างของสองประเภทฉันคิดว่าคุณสามารถเขียนประเภทได้อย่างถูกต้องcompose

compose::ABCDE.A(BC)(DE)A((DC)B((CD)E))

นี้ยังคงค่อนข้างตรงไปตรงมา: composeใช้ฟังก์ชั่นและE ผลกินมันยอดการบริโภคของไม่ได้ผลิตโดยและผลิตบนยอดการผลิตของไม่บริโภคโดยF_2สิ่งนี้ให้กฎสำหรับการแต่งเพลงธรรมดาf 2 : D E B f 2 f 1 D f 1 f 2f1:BCf2:DEBf2f1Df1f2

Γe1:AB.ABΓe2:CD.CDΓe1e2:((CB)A((BC)D))[Comp]

อย่างไรก็ตามฉันไม่รู้ว่าสมมุติฐานนี้สอดคล้องกับอะไรจริง ๆ และฉันก็ไล่ตามมันไปเป็นวงกลมนานพอที่ฉันคิดว่าฉันเลี้ยวผิด มันเป็นความแตกต่างง่ายๆของ tuples ไหม?

A.()A=()A.A()=AABCD.ABCD=BD iff A=Cotherwise=undefined

มีบางสิ่งที่แตกสลายอย่างมากเกี่ยวกับเรื่องนี้ที่ฉันไม่เห็นหรือว่าฉันชอบเส้นทางที่ถูกต้อง? (ฉันอาจบอกปริมาณของสิ่งนี้ผิดและชื่นชมการแก้ไขในพื้นที่นั้นด้วย)


คุณใช้ตัวแปรในไวยากรณ์อย่างไร คำถามนี้จะช่วยคุณในการจัดการ "subtyping" ที่คุณต้องการ
jmad

1
@jmad: ฉันไม่แน่ใจว่าฉันเข้าใจคำถาม ตัวแปรประเภทเป็นเพียงเพื่อประโยชน์ในการกำหนดรูปแบบประเภทอย่างเป็นทางการและภาษาเองไม่มีตัวแปรเลยเพียงแค่คำจำกัดความซึ่งสามารถ [ซ้ำกัน] ซ้ำ
Jon Purdy

ยุติธรรมพอสมควร คุณพูดได้ไหมว่าทำไม (อาจเป็นตัวอย่าง) กฎสำหรับcomposeเข้มงวดเกินไป? ฉันมีความประทับใจว่านี่เป็นแบบนี้ (เช่นข้อ จำกัดสามารถจัดการได้โดยการรวมเช่นสำหรับการใช้งานเช่นในC=D
like-

@jmad: แน่นอน พิจารณาtwiceกำหนดเป็นdup compose applyซึ่งใช้คำพูดและใช้มันสองครั้ง [1 +] twiceเป็นเรื่องปกติ: คุณเขียนสองฟังก์ชั่นประเภท\แต่ไม่ใช่: ถ้า , ปัญหาคือดังนั้นการแสดงออกจึงไม่ได้รับอนุญาตแม้ว่ามันจะถูกต้องและมี พิมพ์A แน่นอนว่าวิธีแก้ปัญหาคือการวางผู้คัดเลือกไว้ในตำแหน่งที่ถูกต้อง แต่ส่วนใหญ่ฉันสงสัยว่าวิธีการเขียนประเภทของจริงโดยไม่มีคำจำกัดความวงกลม ιι[pop] twiceA AAb.f1,f2:AbAA b .AAbAb.AbbAcompose
Jon Purdy

คำตอบ:


9

Rank-2 typeต่อไปนี้ ดูเหมือนจะเป็นเรื่องทั่วไปเพียงพอ มันมีความหลากหลายมากกว่าชนิดที่เสนอในคำถาม ตัวแปรที่นี่วัดปริมาณชิ้นส่วนต่อเนื่องของสแต็กซึ่งจับฟังก์ชั่นหลายอาร์กิวเมนต์

compose:ABCδ.δ (α.α AαB) (β.β BβC)δ (γ.γ AγC)

ตัวอักษรกรีกใช้สำหรับตัวแปร rest-of-the-stack เพื่อความชัดเจนเท่านั้น

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

การตรวจสอบประเภทประเภทอันดับ 2 นั้นไม่สามารถอธิบายได้โดยทั่วไปฉันเชื่อว่าแม้ว่าจะมีงานบางอย่างที่ได้ผลดีในทางปฏิบัติ (สำหรับ Haskell):

  • Simon L. Peyton Jones, Dimitrios Vytiniotis, Stephanie Weirich, Mark Shields: การอนุมานประเภทที่ใช้งานได้จริงสำหรับประเภทใดระดับหนึ่งโดยพลการ J. ฟังก์ชั่น โปรแกรม. 17 (1): 1-82 (2007)

กฎประเภทสำหรับการเรียบเรียงคือ:

Γe1:α.α Aα BΓe1:α.α Bα CΓe1 e2:α.α Aα C

ในการทำให้ระบบชนิดทำงานโดยทั่วไปคุณต้องมีกฎความเชี่ยวชาญต่อไปนี้:

Γe:α.α Aα BΓe:α.C Aα C B

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

1
ประเภทสแต็กเป็นจำนวนมากกว่าชิ้นส่วนสแต็กดังนั้นจึงไม่มีปัญหาในการจัดการกับสองฟังก์ชั่นการโต้แย้ง ฉันไม่แน่ใจว่าจะนำไปใช้กับวิธีนี้ได้อย่างไรdup +เนื่องจากไม่ได้ใช้การเขียนตามที่คุณกำหนดไว้ด้านบน
Dave Clarke

Er [dup] [+] composeขวาฉันหมายถึง แต่ฉันอ่านเป็น ; พูด ; แล้วคุณมีและไม่alpha) การซ้อนไม่ถูกต้องเว้นแต่ว่าคุณจะพลิกกองซ้อนเพื่อให้ด้านบนเป็นองค์ประกอบสุดท้าย (ซ้อนกันที่สุด) B × α B = ι × ι ( ι × ι ) × α ι × ( ι × α )αBB×αB=ι×ι(ι×ι)×αι×(ι×α)
Jon Purdy

ฉันอาจสร้างกองซ้อนของฉันในทิศทางที่ผิด ฉันไม่คิดว่าการทำรังมีความสำคัญตราบใดที่คู่ที่สร้างสแต็กไม่ปรากฏในภาษาการเขียนโปรแกรม (ฉันวางแผนที่จะอัปเดตคำตอบของฉัน แต่ต้องทำวิจัยเล็กน้อยก่อน)
Dave Clarke

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