I am trying to learn a bit of Template Haskell and Quasi Quotation, and I am looking for a function that takes a String
and parses it to Q Exp
, so the type is:
String -> Q Exp
Tried searching hoogle, but the results I saw had to do with lifting String literals to Q Exp
, and the closest I found was Language.Haskell.TH.dyn
which does quite what I want, but only for a single variable.
Are there other options? E.g. a special syntax? I'm just in the process of familiarizing myself with [||]
and $()
, so maybe there is something for this purpose too?
An example of how I imagine it would work:
runQ (parse "(1+)") == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
Also, I am aware of this
runQ [| (1+) |] == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
but this wont work with variable strings because -- understandably -- the string inside is taken as a literal.
runQ [| "(1+)" |] == LitE (StringL "(1+)")
Edit (2015-07-25): I've started using haskell-src-meta
, and it seems to work well so far. However it does take quite a bit of time to cabal install
(about 10 minutes on my machine). Which is a shame, my package is actually rather small, and I would like if install could be quick. Anyone knows of a solution that has smaller dependencies?
As everyone has already said
haskell-src-meta
provideswhere
Pat
,Exp
,Type
, andDec
are the same as fromLanguage.Haskell.TH.Syntax
.It does. Fire up GHCi with
ghci -package ghc
(ghc
is a hidden package by default) and you can import theParser
. It has functions to parseString
into preliminary ASTs (whose data declarations are inHsSyn
) for patterns, expressions, types, and declarations.Looking inside
HsSyn
, its obvious that the AST isn't quite the same as the one inLanguage.Haskell.TH.Syntax
. Open up bothHsExpr
andExp
and side by side you'll see that the latter is filled with types likePostTc id <some-other-type>
andPostRn id <some-other-type>
. As the AST is passed from the parser to the renamer to the type checker, these bits and pieces are all slowly filled in. For example, we don't even know the fixities of operators until we get to type-checking!In order to make the functions we want, we would need to run much more than just the parser (at least the renamer and type checker too, maybe more). Imagine that: every time you want to parse even a small expression like
"1 + 2"
you'll still have to type check a bunch of imports. Even then, converting back to theLanguage.Haskell.TH.Syntax
wouldn't be a walk in the park: GHC has a variety of peculiarities like its own special global way of storing names and identifiers.That's the cool part! Unlike
Exp
,HsExpr
hasHsSplice
for representing splices. Look at the types for the first two constructors:Notice that they aren't storing
String
, they are storing an AST already! Splices get parsed at the same time as the rest of the AST. And just like the rest of the AST, the splices will get passed along to the renamer, type checker, etc. where missing information will be filled in.Probably not. But extricating it from the rest of GHC may be quite difficult. If to use GHC's parser we have to also run the type-checker and the renamer, it may be more elegant and simple to just use a standalone parser like
haskell-src-exts
(which is whatHaskell-src-meta
depends on) that is able to do everything in one pass (fixities, for example, are one of the things you have to give ahead of time to this parser).