1. ホーム

[解決済み】テンプレートHaskellで関連する型の同義語を取得する

2022-04-17 06:46:42

質問

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 で template-haskell パッケージのバージョン 2.9.0.0 で発生しました。また、GHC 7.4.2 で template-haskell パッケージのバージョン 2.7.0.0 でも発生しました。 (私はGHC 7.6.*では確認しませんでしたが、おそらくそこにもあったと思います。) 私はどのバージョンのGHCでも解決策に興味があります("これはGHCバージョンでだけ修正されました)。 V ")。

解決方法は?

誰も要求していないので、実装されていません。

奇妙なことに、THは独自のASTを使用しており、コンパイラの内部ASTに従わないのです。その結果、どんな新しい機能(例えば、関連する型ファミリ)も、THを通して自動的に利用できるわけではありません。誰かがチケットを開いて、それを実装する必要があります。

参考:内部 reifyClass 機能 無視 が返すタプルの5番目の要素である)。 classExtraBigSig の定義も参照してください。 ClassATItem .)

技術的には、関連する型ファミリーのサポートを reify しかし、おそらくTH APIに後方互換性のない変更が必要になるでしょう。例えば、TH APIのASTは関連する型のデフォルトをサポートしていないようです。

追加されました。 現在では 実装 (APIを変更することなく)そしておそらく次の ghc をリリースしました。