我正在为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; (*^) = (*)
|])
但是,这很糟糕:
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
时 TH 都会创建一个新的、唯一的名称,当然,只有当这些类型相同时,定义才会起作用。
有没有办法用牛津括号获得我想要的行为,或者我是否必须退回到好的旧词法范围和Language.Haskell.TH
组合器?我知道使用 CPP 可能会更容易,但我想借此机会学习一些 TH。