How to include code in different places during compilations in Haskell? - haskell

Quasi-quotes allow generating AST code during compilations, but it inserts generated code at the place where Quasi-quote was written. Is it possible in any way to insert the compile-time generated code elsewhere? For example in specific module files which are different from the one where QQ was written? It would depend on hard-coded module structure, but that's fine.
If that's not possible with QQ but anyone knows a different way of achieving it, I am open for suggestions.

To answer this, it's helpful to know what a quasi-quoter is. From the GHC Documentation, a quasi-quoter is a value of
data QuasiQuoter = QuasiQuoter { quoteExp :: String -> Q Exp,
quotePat :: String -> Q Pat,
quoteType :: String -> Q Type,
quoteDec :: String -> Q [Dec] }
That is, it's a parser from an arbitrary String to one or more of ExpQ, PatQ, TypeQ, and DecQ, which are Template Haskell representations of expressions, patterns, types, and declarations respectively.
When you use a quasi-quote, GHC applies the parser to the String to create a ExpQ (or other type), then splices in the resulting template haskell expression to produce an actual value.
It sounds like what you're asking to do is separate the quasiquote parsing and splicing, so that you have access to the TH expression. Then you can import that expression into another module and splice it there yourself.
Knowing the type of a quasi-quoter, it's readily apparent this is possible. Normally you use a QQ as
-- file Expr.hs
eval :: Expr -> Integer
expr = QuasiQuoter { quoteExp = parseExprExp, quotePat = parseExprPat }
-- file Foo.hs
import Expr
myInt = eval [expr|1 + 2|]
Instead, you can extract the parser yourself, get a TH expression, and splice it later:
-- file Foo.hs
import Expr
-- run the QQ parser
myInt_TH :: ExpQ
myInt_TH = quoteExp expr "1 + 2"
-- file Bar.hs
import Foo.hs
-- run the TH splice
myInt = $(myInt_TH)
Of course if you're writing all this yourself, you can skip the quasi-quotes and use a parser and Template Haskell directly. It's pretty much the same thing either way.

Related

Names with single quotes in Template Haskell

Normally, when using Template Haskell, names of bindings and data constructors are quoted by prefixing them with a single quote:
showName, justName :: Name
showName = 'show
justName = 'Just
Unfortunately, this doesn't work for names whose second character is a single quote, because two single quotes with a single character between them are interpreted as a character literal. How can I work around this?
Edit: It seems the user's guide is wrong about there not being an escape mechanism! You can just add a space after the initial single quote. So... don't use the below hack.
It's possible to work around this limitation using expression quoting and a bogus Quote instance.
{-# LANGUAGE DerivingVia #-}
module ExtractName (extractName) where
import Data.Functor.Identity
import GHC.Stack
import Language.Haskell.TH.Syntax
extractName :: HasCallStack => Id Exp -> Name
extractName m = case unId m of
VarE x -> x
ConE x -> x
_ -> withFrozenCallStack $ error extractNameError
newtype Id a = Id {unId :: a}
deriving (Functor, Applicative, Monad) via Identity
-- This is bogus, but good enough for what we're doing.
instance Quote Id where
newName _ = withFrozenCallStack $ error extractNameError
extractNameError :: String
extractNameError =
"extractName: the argument must be an expression quote containing a\n"
++ "single bare name, such as [| f'1 |]"
Now you can write, for example,
f' :: Int
data Foo = B'ar
f'Name, b'arName :: Name
f'Name = extractName [| f' |]
b'arName = extractName [| B'ar |]
How does this work? An expression quote will produce an Exp in an arbitrary monad implementing Quote. In general, desugaring expression quotes may require the newName method, to desugar things like lets and lambda expressions. However, it does not need newName to desugar a plain old binding or data constructor. So we can write a bogus Quote implementation for an Identity-like type that will work for the sorts of quoted expressions we need. Once we've unwrapped the expression, we can extract the name from it.

Is there a way to prevent Data.Generics.Alloy.GenInstances from scanning Data.Text.Internal?

I need to do transformations on an AST; here's a portion of the AST:
data Expr
= BinExpr { beOp :: BinaryOp
, beLeft :: Expr
, beRight :: Expr }
| Name Text
| IntegerLit Integer
| StringLit Text
deriving (Data, Typeable)
And this is a fairly complex AST, so there are many types involved.
I'm using alloy to generate the generic transformations, specifically:
autoGen :: IO ()
autoGen = do
createDirectoryIfMissing True baseDir
writeInstancesTo inst doc imports targetFile
where
inst = allInstances GenWithoutOverlapped
doc = [genInstance (undefined :: Doc)]
imports = header ++ instanceImports
Now, this was fine when using String, but I'm trying to migrate to Data.Text. When the code generation runs, it's reading into the internals of Data.Text like so:
instance (Alloy ([(GHC.Types.Char)]) (f :- ops) BaseOp) =>
Alloy ((Data.Text.Internal.Text)) BaseOp (f :- ops) where
transform _ ops (Data.Text.Internal.pack a0)
= Data.Text.Internal.pack
(transform ops BaseOp (a0))
I believe pack is tied to GHC internals so that's not a valid pattern match, and regardless, having the code mucking with the internals of a Data.Text is liable to break the invariants. (Edit: it looks like there's an instance Data Text where gfoldl f z txt = z packf(unpack txt) declaration, but regardless, I don't need/want to traverse Text values.)
Is there a way to force Alloy to treat a type as atomic? I'm hoping to avoid a newtype to wrap Text as all the code working with ASTs would need to deal with it, which rather defeats the purpose of using generics to avoid boilerplate.
Maybe try this trick: we parameterize the Expr type to override the Data instance used for Text when deriving instances with alloy.
data Expr_ text
= BinExpr { beOp :: BinaryOp
, beLeft :: Expr_ text
, beRight :: Expr_ text }
| Name text
...
| StringLit text
The rest of the code base can use this synonym, hopefully without breaking too much with type inference issues.
type Expr = Expr_ Text
But for Data-generic operations, we use a newtype wrapper around Text and make it behave like a nullary constructor, hoping alloy doesn't need the result of gunfold (or perhaps you could make it behave like a string using pattern synonyms).
newtype DataText = DataText Text
instance Data DataText where
gunfold _ f _ = f undefined
...
autoGen will then specialize everything at DummyText.
Use Data.Coerce.coerce to easily convert between functions on Expr_ DataText and Expr.
coerce :: Expr_ DataText -> Expr
coerce :: Expr -> Expr_ DataText
coerce :: (Expr_ DataText -> Expr_ DataText) -> Expr -> Expr
This might be used to write instances of alloy's type classes for Expr, based on the instances that were derived from you. It's a bit of boilerplate, but hopefully it can be contained and hidden without affecting the rest of the code.

Compiling a String into an Exp with TemplateHaskell

I'm looking for a way to compile a string of a valid Haskell expression code into a TH Exp.
E.g., if there existed an appropriate function, I'd expect it to behave the following way:
> $(theFunctionImLookingFor "\a -> a + 1") 2
3
I've already looked for the implementation of quoteExp :: String -> Q Exp for the underlying QuasiQuoter of [e|..|], but it seems to be magic and there is none.
The function you are looking for is parseExp from the Language.Haskell.Meta.Parse module in the haskell-src-meta package.

Is there a nice(r) way of writing this Template Haskell code involving singleton data types?

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...)
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]
a hack that parses an interpolated string rather than constructing the AST:
makeU1 :: String -> Q [Dec]
makeU1 = makeSingletonDeclaration >>> parseDecs >>> fromRight >>> return
makeSingletonDeclaration :: String -> String
makeSingletonDeclaration name = [qq|data {name} = {name} deriving (Show)|]
where:
parseDecs :: String -> Either String [Dec]
usage:
makeU1 "T"
main = print T
it needs these packages:
$ cabal install haskell-src-exts
$ cabal install haskell-src-meta
$ cabal install interpolatedstring-perl6
runnable script:
https://github.com/sboosali/haskell/blob/0794eb7a52cf4c658270e49fa4f0d9e53c4b0ebf/TemplateHaskell/Splice.hs

looking for a way to add reserved words in data definitions in haskell

As the title says im trying to build an interpreter for Imperative languages in Haskell. Iv done 90% of it, nevertheless, im trying to build If statements, and my question is, how will i define a new datatype lets say :
data x = if boolExp then exp else exp.
I understand that i could re-write this with something like doIf boolExp exp exp. But i would like to see if i could use those reserved keywords just for fun (and maybe conciseness).
Note that both boolExp and exp are defined in my language and work correctly( i even evaluate them to get the actual expression "value").
So bottom line is, how will i add reserved keywords in my data definition as required above?
The closest you can get is the RebindableSyntax extension in GHC, which treats if cond then truePart else falsePart as if you had written ifThenElse cond truePart falsePart, with whatever ifThenElse is in scope.
You can't use this for a data constructor, but you can write something like this:
{-# LANGUAGE RebindableSyntax #-}
import Prelude
data BoolExp = Foo
deriving Show
data Exp = If BoolExp Exp Exp | Bar
deriving Show
ifThenElse :: BoolExp -> Exp -> Exp -> Exp
ifThenElse = If
example = if Foo then Bar else Bar
main = print example
Running this prints If Foo Bar Bar.
However, unless you're writing some kind of internal DSL where this would make sense, I strongly recommend just sticking with the regular syntax like If cond truePart falsePart. Writing it this way has no real benefit and serves only to confuse people when reading your code.
Here's one dumb way to get the kind of syntax you want:
data If a = If Bool () a () a
if_ = If
then_ = ()
else_ = ()
expr :: If Int
expr = if_ (3 > 4) then_ 0 else_ 1
But like hammar said, if you want to actually make use of the keywords if, then, and else, you'll need to use RebindableSyntax, or some other preprocessor/macro, otherwise you'll be in conflict with Haskell syntax.
Besides the suggestions already given, you can also use the quasiquote feature of Template Haskell to create whatever syntax you want.

Resources