Is there a nice(r) way of writing this Template Haskell code involving singleton data types?
haskell, template-haskell
Solution
From the Template Haskell documentation:
A splice can occur in place of
- an expression; the spliced expression must have type Q Exp
- an type; the spliced expression must have type Q Typ
- a list of top-level declarations; the spliced expression must have type Q [Dec]
So e.g. constructor names simply cannot be spliced in the current version of Template Haskell.
I don't think there's much you can do to simplify this use-case (barring constructing the whole declaration as a string and transforming it into a `Dec` via `toDec` in `haskell-src-meta`).
You might consider simply binding the different parts of the declaration to local variables. While more verbose, it makes the code a bit easier to read.
declareSingleton :: String -> Q [Dec]
declareSingleton s = return [DataD context name vars cons derives] where
context = []
name = mkName s
vars = []
cons = [NormalC name fields]
fields = []
derives = [''Eq, ''Ord]
Problem
I've just started to use Template Haskell (I've finally got a use case, yay!) and now I'm cognitively stuck. What I'm trying to do is generating a singleton datatype declaration of the form ``` data $V = $V deriving (Eq,Ord) ``` starting from a name `V` (hopefully starting with an uppercase character!). To be explicit, I'm trying to write a function `declareSingleton` of type `String -> DecsQ` (I should mention here I'm using GHC 7.6.1, template-haskell version 2.8.0.0) such that the splice ``` $(declareSingleton "Foo") ``` is the equivalent of ``` data Foo = Foo deriving (Eq,Ord) ``` I've got the following code working and doing what I want, but I'm not very happy with it: ``` declareSingleton :: String -> Q [Dec] declareSingleton s = let n = mkName s in sequence [ dataD (cxt []) n [] [normalC n []] [''Eq,''Ord] ] ``` I was hoping to get something like the following to work: ``` declareSingleton :: String -> Q [Dec] declareSingleton s = let n = mkName s in [d| data $n = $n deriving (Eq,Ord) |] ``` I've tried, to no avail (but not exhaustively!), various combinations of `$s`, `$v`, `$(conT v)`, `v`, `'v` so I have to suppose my mental model of how Template Haskell works is too simplistic. Am I missing something obvious here, am I confusing type names and constructor names in some essential way, and can I write `declareSingleton` in a nice(r) way? If so, how; if not, why not? (Side remark: the Template Haskell API changes rapidly, and I'm happy for that - I want this simple type to eventually implement a multi-parameter type class with an associated type family - but the churn the API is currently going through doesn't make it easy to search for tutorials! There's a huge difference how TH was implemented in 6.12.1 or 7.2 (when most of the existing tutorial were written) versus how it works nowadays...)