En utilisant le modèle Haskell, comment puis-je épisser le même type dans plusieurs emplacements?

StackOverflow https://stackoverflow.com/questions/8410761

  •  29-10-2019
  •  | 
  •  

Question

Je définis les instances de cours de espace vectoriel pour le Opengl Types, et pour épargner mes muscles de frappe, je veux utiliser le modèle Haskell pour écrire un tas des instances pour moi.

J'ai commencé petit en définissant la fonction pour dériver des instances pour 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
  |])

Cela fonctionne bien, mais notez que je ne fais que l'épissage $t Une fois entre les supports d'Oxford. Maintenant, la fonction à dériver VectorSpace instances:

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

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

La différence entre t_ts et t_tt dans l'erreur me dit que cela crée un nouveau nom unique à chaque fois que j'épisse $t, quand bien sûr, la définition ne fonctionnera que si ces types sont les mêmes.

Existe-t-il un moyen d'obtenir le comportement que je veux avec les supports d'Oxford, ou devrai-je retomber sur la bonne vieille portée lexicale et la Language.Haskell.TH Combinateurs? Je sais que ce serait probablement plus facile avec le CPP, mais je veux profiter de cette occasion pour en apprendre un.

Était-ce utile?

La solution

Je pense que vous devrez utiliser le Language.Haskell.TH Combinateurs. Voir les billets suivants:

Cela est très simple. Je commencerais par cela (légèrement formaté)

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

De là, il est assez simple de voir comment construire des instances à l'aide des combinateurs. Notez également que vous pouvez mélanger la citation avec TH, une expression citée [| some code |] :: ExpQ, ce qui est souvent utile pour créer des corps de fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top