Data constructor in template haskell

家住魔仙堡 提交于 2019-12-05 15:41:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!