Data constructor in template haskell
Asked Answered
T

1

11

I'm trying to create the ring Z/n (like normal arithmetic, but modulo some integer). An example instance is Z4:

instance Additive.C Z4 where
  zero = Z4 0
  (Z4 x) + (Z4 y) = Z4 $ (x + y) `mod` 4

And so on for the ring. I'd like to be able to quickly generate these things, and I think the way to do it is with template haskell. Ideally I'd like to just go $(makeZ 4) and have it spit out the code for Z4 like I defined above.

I'm having a lot of trouble with this though. When I do genData n = [d| data $n = $n Integer] I get "parse error in data/newtype declaration". It does work if I don't use variables though: [d| data Z5 = Z5 Integer |], which must mean that I'm doing something weird with the variables. I'm not sure what though; I tried constructing them via newName and that didn't seem to work either.

Can anyone help me with what's going on here?

Taxonomy answered 27/9, 2011 at 1:0 Comment(1)
I'm not a Template Haskell wizard, but I'm betting the people who are will want to see your Template Haskell code.Literatim
P
13

The Template Haskell documentation lists the things you are allowed to splice.

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]

In both occurrences of $n, however, you're trying to splice a name.

This means you can't do this using quotations and splices. You'll have to build declaration using the various combinators available in the Language.Haskell.TH module.

I think this should be equivalent to what you're trying to do.

genData :: Name -> Q [Dec]
genData n = fmap (:[]) $ dataD (cxt []) n []
                           [normalC n [strictType notStrict [t| Integer |]]] []

Yep, it's a bit ugly, but there you go. To use this, call it with a fresh name, e.g.

$(genData (mkName "Z5"))
Pfaff answered 27/9, 2011 at 1:35 Comment(3)
Could you include an example of its use? I modified what you had slightly and just threw $(genData "Foo") as a top-level into my code, but if I do :i Foo in ghci it doesn't find anything.Taxonomy
@Xodarap: Use mkName to make a Name from a String. I've added an example. I guess you may have used newName, which adds some stuff at the end to ensure that the name is unique, so :info would not show it. You should be able to see it using :browse, though.Pfaff
Thanks! this was my problem exactly.Taxonomy

© 2022 - 2024 — McMap. All rights reserved.