Я определяю экземпляры классов из vector-space для OpenGL, и, чтобы избавить меня от печатающих мышц, я хочу использовать Template 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; (*^) = (*)
|])
Но это barfs:
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.