Mendapatkan sinonim jenis terkait dengan template Haskell

257

Bisakah Template Haskell mengetahui nama dan / atau deklarasi dari sinonim tipe terkait yang dinyatakan dalam kelas tipe? Saya berharap reifyakan melakukan apa yang saya inginkan, tetapi sepertinya tidak memberikan semua informasi yang diperlukan. Ini berfungsi untuk mendapatkan tanda tangan jenis fungsi:

% 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)))])
       []

Namun, menambahkan sinonim tipe terkait ke kelas menyebabkan tidak ada perubahan (hingga penamaan ulang) di output:

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)))])
       []

Jika saya tahu nama F, saya dapat mencari informasi tentang itu:

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

Tapi saya tidak dapat menemukan nama itu F. Bahkan jika saya menambahkan turunan dari kelas tipe, InstanceDtidak ada informasi tentang definisi:

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)))
                  []]

Jika reifytidak berhasil, apakah ada solusi, selain mendaftar sinonim jenis rekanan secara manual?

Masalah ini hadir di GHC 7.8.3 dengan versi 2.9.0.0 dari paket template-haskell; itu juga hadir di GHC 7.4.2 dengan versi 2.7.0.0 dari paket template-haskell. (Saya tidak memeriksa GHC 7.6. *, Tapi saya membayangkan itu ada di sana juga.) Saya tertarik dengan solusi untuk semua versi GHC (termasuk "ini hanya diperbaiki di GHC versi V ").

Antal Spector-Zabusky
sumber
2
Sudahkah Anda melihat reifyInstances?
Kwarrtz
2
@ Kwarrtz: Saya baru saja mencobanya sekarang. Tapi itu tidak berhasil; itu hanya menimbulkan yang sama InstanceDseperti yang saya lihat dengan reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])mengevaluasi [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], yang tidak memiliki contoh keluarga jenis.
Antal Spector-Zabusky
1
Saya merasa aneh karena reifytidak mengembalikan informasi yang diperlukan. Mungkin showmenyembunyikan beberapa informasi? Sudahkah Anda mencoba memeriksa Infoobjek secara langsung?
Kwarrtz
@Kwarrtz: Aku takut Info's Showinstance hanya berasal satu, dan sama untuk Showcontoh untuk Dec. Namun, saya juga dapat memeriksa secara langsung, seperti yang Anda minta, dan tidak: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")menghasilkan just a SigD- itu benar-benar satu-satunya di [Dec]dalam ClassD! (membutuhkan LambdaCase). Saya setuju itu aneh; itu sebabnya saya menanyakan pertanyaan ini :-)
Antal Spector-Zabusky
1
@ Bel: Saya pikir kita sepakat - komentar awal Anda mengatakan itu tidak cukup untuk menarik ide cemerlang, tapi itu memang menarik jawaban Yuras! Saya sangat setuju tentang apa jawaban yang baik :-)
Antal Spector-Zabusky

Jawaban:

15

Itu tidak diterapkan karena tidak ada yang memintanya.

Yang aneh adalah bahwa TH menggunakan AST sendiri, yang tidak mengikuti AST kompiler internal. Akibatnya, fitur baru apa pun (mis. Keluarga tipe terkait) tidak tersedia secara otomatis melalui TH. Seseorang harus membuka tiket dan menerapkannya.

Untuk referensi: reifyClassfungsi internal mengabaikan keluarga tipe terkait (ini adalah elemen ke-5 dari tuple yang dikembalikan oleh classExtraBigSig, lihat juga definisi ClassATItem.)

Secara teknis seharusnya mudah untuk menerapkan dukungan keluarga tipe terkait reify, tetapi kemungkinan besar itu akan memerlukan perubahan yang tidak kompatibel ke belakang di TH API, misalnya karena AST tampaknya tidak mendukung default jenis terkait.

Ditambahkan: Sekarang diterapkan (tanpa perubahan API btw) dan mungkin akan tersedia di ghcrilis berikutnya .

Yura
sumber
1
@ AntalS-Z Maksud saya FamilyDtidak mendukung default jenis sinonim terkait . Anda mungkin tidak menggunakannya, tetapi solusi lengkap mungkin memerlukan perubahan API.
Yuras
5
@ Bel, membiarkan karunia terbuka sampai akhir juga cenderung membantu jawaban yang baik menarik suara, jadi itu cara yang lebih efektif untuk menghargai jawaban yang baik daripada memberikannya dengan cepat.
dfeuer
1
Masa hadiah berakhir. Ini adalah jawaban terbaik (dan satu-satunya), sampai atau kecuali laporan bug # 10891 diselesaikan . Mungkin ide yang baik untuk memasukkan tautan ke laporan bug dalam jawaban Anda.
Abel
1
FYI, # 10891 sudah diperbaiki dan menunggu untuk digabung.
sinan
1
@SwiftsNamesake AFAIK ghc devs ingin mengubah AST internal secara bebas tanpa melanggar API TH. Mungkin ada alasan lain juga.
Yuras