การใช้คำพ้องความหมายประเภทที่เกี่ยวข้องกับแม่แบบ Haskell


257

Template Haskell สามารถค้นหาชื่อและ / หรือการประกาศคำพ้องความหมายประเภทที่เกี่ยวข้องที่ประกาศไว้ในคลาสประเภทได้หรือไม่ ฉันคาดว่าreifyจะทำสิ่งที่ฉันต้องการ แต่ดูเหมือนจะไม่ได้ให้ข้อมูลที่จำเป็นทั้งหมด มันทำงานเพื่อรับลายเซ็นประเภทฟังก์ชั่น:

% ghci
GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
...
Prelude> -- I'll be inserting line breaks and whitespace for clarity
Prelude> -- in all GHCi output.
Prelude> :set -XTemplateHaskell 
Prelude> import Language.Haskell.TH
Prelude Language.Haskell.TH> class C a where f :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C)
ClassI (ClassD [] Ghci1.C [PlainTV a_1627398388] []
               [SigD Ghci1.f
                     (ForallT [PlainTV a_1627398388]
                              [ClassP Ghci1.C [VarT a_1627398388]]
                              (AppT (AppT ArrowT (VarT a_1627398388))
                                    (ConT GHC.Types.Int)))])
       []

อย่างไรก็ตามการเพิ่มคำพ้องความหมายประเภทที่เชื่อมโยงกับคลาสทำให้ไม่มีการเปลี่ยนแปลง (จนถึงการเปลี่ยนชื่อ) ในผลลัพธ์:

Prelude Language.Haskell.TH> :set -XTypeFamilies 
Prelude Language.Haskell.TH> class C' a where type F a :: * ; f' :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
               [SigD Ghci3.f'
                     (ForallT [PlainTV a_1627405973]
                              [ClassP Ghci3.C' [VarT a_1627405973]]
                              (AppT (AppT ArrowT (VarT a_1627405973))
                                    (ConT GHC.Types.Int)))])
       []

หากฉันรู้ชื่อของFฉันสามารถค้นหาข้อมูลเกี่ยวกับมัน:

Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''F)
FamilyI (FamilyD TypeFam
                 Ghci3.F
                 [PlainTV a_1627405973]
                 (Just StarT))
        []

แต่ฉันไม่สามารถหาชื่อของFในตอนแรก แม้ว่าฉันจะเพิ่มอินสแตนซ์ของคลาสชนิด แต่InstanceDไม่มีข้อมูลเกี่ยวกับคำนิยาม:

Prelude Language.Haskell.TH> instance C' [a] where type F [a] = a ; f' = length
Prelude Language.Haskell.TH> f' "Haskell"
7
Prelude Language.Haskell.TH> 42 :: F [Integer]
42
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
               [SigD Ghci3.f'
                     (ForallT [PlainTV a_1627405973]
                              [ClassP Ghci3.C' [VarT a_1627405973]]
                              (AppT (AppT ArrowT (VarT a_1627405973))
                                    (ConT GHC.Types.Int)))])
       [InstanceD []
                  (AppT (ConT Ghci3.C')
                        (AppT ListT (VarT a_1627406161)))
                  []]

หากreifyไม่สามารถใช้งานได้มีวิธีแก้ไขอื่นนอกเหนือจากการระบุชื่อคำพ้องความหมายประเภทเชื่อมโยงด้วยตนเองหรือไม่?

ปัญหานี้มีอยู่ใน GHC 7.8.3 พร้อมกับเวอร์ชัน 2.9.0.0 ของแพ็คเกจ template-haskell มันยังมีอยู่ใน GHC 7.4.2 ด้วยรุ่น 2.7.0.0 ของแพ็คเกจ template-haskell (ฉันไม่ได้ตรวจสอบ GHC 7.6. * แต่ฉันคิดว่ามันมีอยู่ด้วย) ฉันสนใจวิธีแก้ปัญหาสำหรับ GHC รุ่นใด ๆ (รวมถึง "สิ่งนี้ได้รับการแก้ไขใน GHC เวอร์ชันV " เท่านั้น)


2
มีคุณดูreifyInstances?
Kwarrtz

2
@Kwarrtz: ฉันเพิ่งลองตอนนี้ มันไม่ทำงานแม้ว่า; มันแค่ก่อให้เกิดInstanceDs เดียวกันกับที่ฉันเห็นด้วยreify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])ประเมินให้[InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []]ซึ่งขาดอินสแตนซ์ตระกูลประเภท
Antal Spector-Zabusky

1
ฉันพบว่ามันแปลกที่reifyไม่ส่งคืนข้อมูลที่จำเป็น อาจshowซ่อนข้อมูลบางส่วนอยู่หรือ คุณลองตรวจสอบInfoวัตถุโดยตรงหรือไม่
Kwarrtz

@Kwarrtz: ฉันกลัวInfo's Showเช่นเป็นเพียงการได้มาหนึ่งและเหมือนกันสำหรับอินสแตนซ์สำหรับShow Decแต่ผมยังสามารถตรวจสอบได้โดยตรงที่คุณถามและไม่มี: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")ผลิตjust a SigD- ที่จริงมีเพียงสิ่งเดียวใน[Dec]ในClassD! (ต้องมีLambdaCase) ฉันเห็นว่ามันแปลก นั่นเป็นเหตุผลที่ฉันถามคำถามนี้ :-)
Antal Spector-Zabusky

1
@Abel: ผมคิดว่าเรากำลังอยู่ในข้อตกลงความรุนแรง - ความคิดเห็นเดิมของคุณบอกว่ามันไม่เพียงพอที่จะดึงดูดความคิดที่ยอดเยี่ยม แต่มันไม่ดึงดูดคำตอบของ Yuras! ฉันอย่างเห็นด้วยเกี่ยวกับสิ่งที่เป็นคำตอบที่ดีคือ :-)
Antal สเปคเตอร์-Zabusky

คำตอบ:


15

ไม่ได้ใช้งานเพราะไม่มีใครร้องขอ

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

สำหรับการอ้างอิง: reifyClassฟังก์ชั่นภายในจะไม่สนใจตระกูลประเภทที่เกี่ยวข้อง (มันเป็นองค์ประกอบที่ 5 ของ tuple ที่ส่งคืนโดยclassExtraBigSigให้ดูที่นิยามของClassATItem)

ในทางเทคนิคแล้วมันควรจะง่ายต่อการปรับใช้การสนับสนุนประเภทครอบครัวที่เกี่ยวข้องในreifyแต่ส่วนใหญ่แล้วมันจะต้องมีการเปลี่ยนแปลงย้อนหลังเข้ากันไม่ได้ใน TH API เช่นเนื่องจาก AST ดูเหมือนจะไม่สนับสนุนค่าเริ่มต้นของประเภทที่เกี่ยวข้อง

เพิ่ม:ตอนนี้มีการใช้งาน (ไม่มีการเปลี่ยนแปลง API btw) และอาจจะมีในghcรุ่นถัดไป


1
@ AntalS-Z ฉันหมายความว่าFamilyDไม่สนับสนุนการเชื่อมโยงประเภทค่าเริ่มต้นไวพจน์ คุณอาจไม่ได้ใช้ แต่วิธีการแก้ปัญหาอย่างสมบูรณ์อาจต้องเปลี่ยน API
Yuras

5
@Abel การเปิดรับรางวัลจนจบก็มีแนวโน้มที่จะช่วยให้คำตอบที่ดีดึงดูดการลงคะแนนดังนั้นจึงเป็นวิธีที่มีประสิทธิภาพมากกว่าในการให้รางวัลคำตอบที่ดีกว่าการให้รางวัลอย่างรวดเร็ว
dfeuer

1
ช่วงเวลาเงินรางวัลหมดอายุ นี่คือสิ่งที่ดีที่สุด (และ) คำตอบจนหรือเว้นแต่รายงานข้อผิดพลาด # 10891 ได้รับการแก้ไข อาจเป็นความคิดที่ดีที่จะรวมลิงก์ไปยังรายงานข้อบกพร่องในคำตอบของคุณ
Abel

1
FYI, # 10891 ได้รับการแก้ไขและกำลังรอการผสาน
sinan

1
@SwiftsNamesake AFAIK ghc devs ต้องการเปลี่ยน AST ภายในได้อย่างอิสระโดยไม่ต้องทำลาย API API อาจมีเหตุผลอื่นด้วย
Yuras
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.