11

OpenGLタイプのベクトル空間からクラスのインスタンスを定義しています。タイピングの筋肉を節約するために、TemplateHaskellを使用して一連のインスタンスを作成したいと思います。

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これは問題なく機能しますが、オックスフォードブラケットに1回だけ接続していることに注意してください。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、THがスプライスするたびに新しい一意の名前を作成していることを示しています$t。もちろん、これらのタイプが同じ場合にのみ定義が機能します。

オックスフォードブラケットで必要な動作を実現する方法はありますか、それとも古き良きレキシカルスコープとLanguage.Haskell.THコンビネータにフォールバックする必要がありますか?これはおそらくCPPの方が簡単だと思いますが、この機会にTHを学びたいと思います。

4

1 に答える 1

5

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であるTHを混在させることができることにも注意してください。これは、関数本体を作成するのに役立つことがよくあります。

于 2011-12-07T11:49:01.320 に答える