问题
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?
回答1:
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"))
来源:https://stackoverflow.com/questions/7563092/data-constructor-in-template-haskell