Domanda

Sto definendo istanze di lezioni da vettore-spazio per il OpenGL Tipi e per risparmiare i miei muscoli da digitare, voglio usare il modello Haskell per scrivere un sacco di istanze per me.

Ho iniziato in piccolo definendo la funzione per derivare istanze per 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
  |])

Funziona bene, ma nota che sto solo girando $t una volta tra le staffe di Oxford. Ora, la funzione per derivare VectorSpace istanze:

deriveScalarVectorSpace ts = concat <$> forM (map conT ts) (\t -> [d|    
    instance VectorSpace $t where type Scalar $t = $t; (*^) = (*)
  |])

Ma questo barf:

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
          { *^ = (*) } |]

La differenza tra t_ts e t_tt Nell'errore mi dice che questo sta creando un nuovo nome univoco ogni volta che mi girgo $t, quando ovviamente la definizione funzionerà solo se questi tipi sono uguali.

C'è un modo per ottenere il comportamento che voglio con le parentesi di Oxford, o dovrò ricadere in un buon vecchio ambito lessicale e il Language.Haskell.TH Combinatori? So che questo sarebbe probabilmente più facile con il CPP, ma voglio cogliere l'occasione per imparare un po '.

È stato utile?

Soluzione

Penso che dovrai usare il Language.Haskell.TH Combinatori. Vedi i seguenti biglietti:

Farlo è molto semplice. Inizierei con questo (leggermente formattato)

*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)) []]
]

Da qui, è piuttosto semplice vedere come costruire istanze usando i combinatori. Si noti inoltre che è possibile mescolare citazioni con th, un'espressione citata [| some code |] :: ExpQ, che è spesso utile per creare corpi funzionali.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top