Compiling a String into an Exp with TemplateHaskell - haskell

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.

Related

Test a function's type

I'm new to haskell. I read this answer and I would also like to test the type of my functions, if there is a way to do it.
Here is an example : test.hs
module Test where
import Test.HUnit
test1 = TestCase (assertEqual "test1" 3 (length [1,2,3]))
tests = TestList [test1]
main :: IO Counts
main = runTestTT tests
I'm running the code with runghc test.hs and I get:
Cases: 1 Tried: 1 Errors: 0 Failures: 0
Now, how can I test the type for the length function ?
I have already tried adding a second test test2 = TestCase (assertEqual "test2" "length :: Foldable t => t a -> Int" :type length), but I get this error test.hs:5:77: parse error on input 'type'.
Thanks
Writing a test for a type is almost definitely not what you want. Since Haskell is statically typed, the compiler automatically checks types for you when you compile, with no need to run any code or tests. If length did not have a compatible type, you would get a type error if you tried to load the code at all.
:type is a special command from ghci, not actual Haskell syntax. You can't use it directly in a normal program. There are ways to get a value representing a type but they're somewhat complicated and, again, almost definitely not what you need.
Although I agree with the other answer that the question smells, I think it is worth giving a direct answer anyway. You could put a type assertion in your test suite like this:
module Test where
check_type_of_length :: Foldable t => t a -> Int
check_type_of_length = length
If length can not be given the type you requested, the module will not compile. However, this is not a perfect test: if the type of length is actually more polymorphic than the type you demand, this will still "pass"; thus, for example, the following module still compiles, even though undefined does not have exactly the type Foldable t => t a -> Int.
module Test where
check_type_of_length :: Foldable t => t a -> Int
check_type_of_length = undefined
We can make the test a bit more precise if you want to check a monomorphic type. The idea is to use Typeable, as suggested by #dfeuer. That would look like this:
module Test where
import Data.Typeable
test_type_of_not :: Bool
test_type_of_not = typeOf not == typeOf (undefined :: Bool -> Bool)
If not has the monomorphic type Bool -> Bool, then test_type_of_not will be True; if it has a different monomorphic type, it will be False; and if not suddenly becomes polymorphic, the module will fail to compile with an ambiguity error.
I do not know an analogous way to test that a polymorphic type does not become more polymorphic; you could perhaps do something nasty like running a short bash script that does
echo :t length | ghci
and checking its output, or something more direct with the GHC API. However, an approach like this is likely to be very fragile.

How to work with Regex and OverloadedString

I have been using Text.Regex.Posix in a file, everything works fine so far.
Now, I would like to use OverloadedStrings for something else but in the same file. The problem is when I activate OverloadedString all the code related to regex doesn't compile because the strings becomes ambiguous.
Is there a way to deal with this without having to add type signature to every strings or deactivate OverloadedStrings ?
I see two approaches here. You can do some import shuffling and just alias the functions you need to have less general types, such as
import qualified Text.Regex.Posix as P
import Text.Regex.Posix hiding ((=~))
(=~) :: RegexContext Regex String target => String -> String -> target
(=~) = (P.=~)
Then you don't have to change the code throughout your file. This can lead to confusion though, and it requires FlexibleContexts to work (not a big deal).
Alternatively you can create your own Python-like syntax for specifying the type:
r :: String -> String
r = id
u :: Text -> Text
u = id
b :: ByteString -> ByteString
b = id
example :: Bool
example = r"test" =~ r"te.t"
splitComma :: Text -> Text
splitComma = Data.Text.splitOn (u",")
But this will require you to edit more of your code. It doesn't use any extra language extensions and the code to implement it is very simple, even in comparison to the first method. It Also means that you'll have to use parentheses or $ signs more carefully, but you can also use the r, u, and b functions as, well, functions.

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

How to include code in different places during compilations in 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.

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