テンプレートHaskellを使用して、同じタイプを複数の場所にスプライスするにはどうすればよいですか?
-
29-10-2019 - |
質問
クラスのインスタンスを定義しています ベクトル空間 のために opengl タイプ、そしてタイピング筋肉をspareしまないように、テンプレートのhaskellを使用して、私のためにたくさんのインスタンスを書きたいと思います。
機能を定義してインスタンスを導き出すことから小さく始めました AdditiveGroup
:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Data.VectorSpace.OpenGL.TH where
import Control.Applicative
import Control.Monad
import Data.AdditiveGroup
import Data.VectorSpace
import Language.Haskell.TH
deriveScalarAdditive ts = concat <$> forM (map conT ts) (\t -> [d|
instance AdditiveGroup $t where zeroV = 0; (^+^) = (+); negateV = negate
|])
これは正常に動作しますが、私はスプライシングだけであることに注意してください $t
オックスフォードの括弧内に一度。今、導出する関数 VectorSpace
インスタンス:
deriveScalarVectorSpace ts = concat <$> forM (map conT ts) (\t -> [d|
instance VectorSpace $t where type Scalar $t = $t; (*^) = (*)
|])
しかし、このバーフ:
Type indexes must match class instance head
Found `t_tt' but expected `t_ts'
In the associated type instance for `Scalar'
In the instance declaration for `VectorSpace $t'
In the Template Haskell quotation
[d| instance VectorSpace $t where
type instance Scalar $t = $t
{ *^ = (*) } |]
間の違い t_ts
と t_tt
エラーでは、私がスプライスするたびに新しいユニークな名前を作成していることがわかります $t
, 、もちろん、定義はそれらのタイプが同じ場合にのみ機能する場合にのみ機能します。
オックスフォードのブラケットで私が望む行動を取得する方法はありますか、それとも古き良き語彙の範囲と Language.Haskell.TH
組み合わせ?これはおそらくCPPでより簡単になることを知っていますが、この機会を利用していくつかのTHを学びたいと思います。
解決
使用する必要があると思います Language.Haskell.TH
組み合わせ。次のチケットを参照してください。
そうすることは非常に簡単です。私はこれから始めます(わずかにフォーマットされています)
*Foo Language.Haskell.TH> runQ (deriveScalarAdditive [''Int] ) >>= print
[InstanceD [] (AppT (ConT Data.AdditiveGroup.AdditiveGroup) (ConT GHC.Types.Int))
[ValD (VarP zeroV_12) (NormalB (LitE (IntegerL 0))) [],
ValD (VarP ^+^_13) (NormalB (VarE GHC.Num.+)) [],
ValD (VarP negateV_14) (NormalB (VarE GHC.Num.negate)) []]
]
ここから、コンビネーターを使用してインスタンスを構築する方法を見るのは非常に簡単です。また、引用を引用して引用した表現と混合できることに注意してください [| some code |] :: ExpQ
, 、これはしばしば関数体を作成するのに役立ちます。
所属していません StackOverflow