The encoding package uses HaXml in its build script (in Setup.hs). It happens to use bits of the interface that changed between HaXml-1.19 and HaXml-1.22. It would be nice if the encoding package were able to build with either version. I tried using the usual Cabal trick, namely, doing something like
{-# LANGUAGE CPP #-}
#if MIN_VERSION_HaXml(1,22,0)
-- HaXml-1.22 code
#else
-- HaXml-1.19 code
#endif
...but the magic defines can't exist before the package is configured, and this file is being built to make the configure step possible. What are my options? Is there a way to change the command that cabal-install calls to compile Setup.hs? Is there another mechanism for conditionally selecting code that sidesteps cabal?
The Data.Data interface is capable (just about!) of constructing and deconstructing values of a type that may or may not exist. Unfortunately, HaXml doesn't appear to have Data instances for its types, and you can't define one since you can't refer to the type that might or might not exist, so we have to resort to Template Haskell:
The following module exports qnameCompat:
{-# LANGUAGE TemplateHaskell #-}
module HaXmlCompat (qnameCompat) where
import Language.Haskell.TH
qnameCompat :: Q [Dec]
qnameCompat = do
mi <- maybeReify "N"
case mi of
Nothing -> sequence [
tySynD (mkName "QName") [] [t| String |],
valD [p| toQName |] (normalB [| id |]) [],
valD [p| fromQName |] (normalB [| Just |]) []]
Just (DataConI n _ _ _) -> do
s <- newName "s"
sequence [
valD [p| toQName |] (normalB (conE n)) [],
funD (mkName "fromQName") [
clause [conP n [varP s]] (normalB (appE [| Just |] (varE s))) [],
clause [ [p| _ |] ] (normalB [| Nothing |]) []]]
Just i -> fail $
"N exists, but isn't the sort of thing I expected: " ++ show i
maybeReify :: String -> Q (Maybe Info)
maybeReify = recover (return Nothing) . fmap Just . reify . mkName
When spliced at the top level using Template Haskell, qnameCompat will check if N exists. If it does, it produces the following code:
toQName = N
fromQName (N s) = Just s
fromQName _ = Nothing
If it doesn't, the following is produced:
type QName = String
toQName = id
fromQName = Just
Now you can create and deconstruct Elements, e.g. using the ViewPatterns extension:
myElt :: String -> Element i
myElt = Elem (toQName "elemName") [] []
eltName :: Element i -> String
eltName (Elem (fromQName -> Just n) _ _) = n
ViewPatterns is convenient, but not essential, of course: using ordinary pattern matching on the result of fromQName will work just as well.
(These ideas are what led me to develop the notcpp package, which includes maybeReify and some other useful utilities)
There don't seem to be very many knobs in cabal-install/Distribution/Client/SetupWrapper.hs controlling the compilation of Setup.hs, so your best bet may be to create a stub Setup.hs file which performs the version test, and then hands off to real Setup.hs once it has figured out what the version is.
Another trick is to make a compatibility shim library which your Setup script uses, which has the appropriate version tricks.
But maybe the real question to ask, is this: why is Setup.hs using external libraries?
Related
Is it possible to write code in the following spirit:
data EventTable = "table1" | "table2" | "some_other_table"
case eventTable of
"table1" -> -- do something
"table2" -> -- do something else
"some_other_table" -> -- do something else
"unknown_table"-> -- SHOULD NOT COMPILE
I'm trying to work directly with the string literals that a remote API provides, instead of first mapping them to a regular Haskell sum-type/ADT and having to write serialisation and deserialisation functions for it.
Haskell doesn't have anything like TypeScript's string literal types (which are singleton types: TypeScript will only allow you to use a given string if it can tell that you've checked the string does indeed fit the type), and the best way is probably to just hand-roll a regular datatype and a simple smart constructor. But as #chi points out in the comments, if you have a lot of strings to deal with this is probably a job for code generation.
We'll write a Template Haskell helper to turn splices like
stringLitTy "Foo" ["bar", "baz"]
into a data declaration, a smart constructor, and a toString function:
data Foo = Bar | Baz deriving (Eq, Ord, Bounded, Enum, Show, Read)
mkFoo :: String -> Maybe Foo
mkFoo "bar" = Just Bar
mkFoo "baz" = Just Baz
mkFoo _ = Nothing
fooToString :: Foo -> String
fooToString Bar = "bar"
fooToString Baz = "baz"
The code to do this is simple enough, so if you're not familiar with TH this'll be a good crash course.
First let's create some names for the type and the functions, and a mapping from the string literals to some constructor names.
{-# LANGUAGE TemplateHaskell #-}
module StringLit where
import Data.Char
import Language.Haskell.TH
legaliseCon :: String -> String
legaliseCon (x:xs) = toUpper x : map (\c -> if not (isAlphaNum c) then '_' else c) xs
legaliseFun :: String -> String
legaliseFun (x:xs) = toLower x : map (\c -> if not (isAlphaNum c) then '_' else c) xs
stringLitTy :: String -> [String] -> Q [Dec]
stringLitTy typeName strs =
let tyName = mkName $ legaliseCon typeName
constrName = mkName $ legaliseFun ("mk" ++ typeName)
toStringName = mkName $ legaliseFun (typeName ++ "ToString")
conNames = [(n, mkName $ legaliseCon n) | n <- strs]
in sequenceA [
mkDataDecl tyName (map snd conNames),
mkConstrDecl constrName conNames,
mkToStringDecl toStringName conNames
]
legaliseCon and legaliseFun are blunt instruments to get a string into a form which is valid for a constructor or a function. (There's definitely room for improvement there!) stringLitTy calls mkDataDecl, mkConstrDecl and mkToStringDecl, below, to generate the top-level declarations. They're all pretty simple: mkDataDecl calls dataD to construct the datatype declaration with an appropriate deriving clause.
enumClasses = sequenceA [
[t| Eq |],
[t| Ord |],
[t| Bounded |],
[t| Enum |],
[t| Show |],
[t| Read |]
]
mkDataDecl :: Name -> [Name] -> Q Dec
mkDataDecl tyName conNames =
dataD
(return []) -- datatype context
tyName -- name
[] -- type parameters
Nothing -- kind annotation
[normalC n [] | n <- conNames] -- constructors, none of which have any parameters
enumClasses -- "deriving" classes
mkConstrDecl uses funD to generate the code for the smart constructor (mkFoo), based on the mapping from strings to the generated constructors' names.
mkConstrDecl :: Name -> [(String, Name)] -> Q Dec
mkConstrDecl name map = funD name $ [
clause
[litP $ stringL str] -- the string literal pattern on the LHS
(normalB $ appE [| Just |] (conE con)) -- Just Con on the RHS
[] -- where clauses
| (str, con) <- map]
++ [clause [wildP] (normalB $ [| Nothing |]) []] -- mkFoo _ = Nothing
And mkToStringDecl does much the same, except the constructors are on the left hand side and the string literals are on the right. And there's need for a wildcard clause or the Maybe.
mkToStringDecl :: Name -> [(String, Name)] -> Q Dec
mkToStringDecl name map = funD name [
clause
[conP con []]
(normalB $ litE $ stringL str)
[]
| (str, con) <- map]
So, if I import StringLit in another module and write a splice,
{-# LANGUAGE TemplateHaskell #-}
module Test where
import StringLitTy
stringLitTy "EventTable" ["table1", "table2", "some_other_table"]
I can perform case analysis on the constructors of the generated EventTable type. It's not exactly what you asked for in the question, but I think it gets you 90% of the way there.
tableNumber Table1 = Just 1
tableNumber Table2 = Just 2
tableNumber Some_other_table = Nothing
-- for good measure:
ghci> :l Test
[1 of 2] Compiling StringLitTy ( StringLitTy.hs, interpreted )
[2 of 2] Compiling Test ( Test.hs, interpreted )
Ok, modules loaded: Test, StringLitTy.
ghci> :bro
data EventTable = Table1 | Table2 | Some_other_table
mkEventTable :: [Char] -> Maybe EventTable
eventTableToString :: EventTable -> [Char]
ghci> tableNumber Table1
Just 1
Oh, one more thing: since the Q monad allows you to run IO actions in your splices, you can (say) query the database to get your table names. Template Haskell programming is "just programming", so you can do all the usual Monad stuff with Q (like traverse):
getTablesFromDb :: IO [(String, [String])]
getTablesFromDb = {- ... -}
mkTables :: Q [Dec]
mkTables = do
tables <- runIO getTablesFromDb
concat <$> traverse (uncurry stringLitTy) tables
I have a TemplateHaskell function creating a class name:
test :: Q [Dec]
test = do
clsname <- newName "A"
a <- newName "a"
return [
ClassD [] clsname [PlainTV a] [][]
]
The classname is generated with newName, so should be conflict free (the reason is I create the instances directly in TH and don't need it to be visible).
test
test
Schema.hs:27:1: error:
Multiple declarations of ‘A’
Declared at: Schema.hs:26:1
Schema.hs:27:1
However testing it with Debug.Trace, the name of A is indeed something like A_1627476119. This is the same in both GHC 7.10.3 and GHC8. Is this a bug or do I understand it wrong?
newName doesn't work the way you're imagining. It doesn't create a random unused symbol using the supplied string merely as a prefix, and -- as far as I can tell -- Template Haskell doesn't have a standard function to do that. However you can get the equivalent effect with:
gensym :: String -> Q Name
gensym pfx = mkName . show <$> newName pfx
which should work for your anonymous classes:
test :: Q [Dec]
test = do
clsname <- gensym "A" -- use gensym here
a <- newName "a" -- this is fine, though
return [
ClassD [] clsname [PlainTV a] [][]
]
If you're interested in the longer explanation, what newName does do is create a name that cannot be captured by "deeper" bindings, but it does this by attaching additional information to the created Name object, not by mangling the actual name. If such a Name is used to create a binding, the binding uses the original supplied name, not a mangled version.
To see this, note first that the Name created by mkName has more structure than its printable representation suggests:
GHCi> :m Language.Haskell.TH Language.Haskell.TH.Syntax
GHCi> nm <- runQ (newName "foo")
GHCi> nm
foo_16
GHCi> let Name occname nmtype = nm
GHCi> occname
OccName "foo"
GHCi> nmtype
NameU 16
GHCi>
Second, note that the quotation:
[d| one = 1 |]
is equivalent to the following do-block using newName:
do nm <- newName "one"
decl <- valD (varP nm) (normalB (litE (integerL 1))) []
return [decl]
so you can write the following:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
$(do nm <- newName "one"
decl <- valD (varP nm) (normalB (litE (integerL 1))) []
return [decl])
main = print one
illustrating that the "one" name created by newName can be used to create a top-level binding that is referenced in the main function using its plain, unadorned, name: one. (If you created an extra copy of the splice here, you'd get the same "multiple declarations" error you got with your classes.)
Is it possible to generate and run TemplateHaskell generated code at runtime?
Using C, at runtime, I can:
create the source code of a function,
call out to gcc to compile it to a .so (linux) (or use llvm, etc.),
load the .so and
call the function.
Is a similar thing possible with Template Haskell?
Yes, it's possible. The GHC API will compile Template Haskell. A proof-of-concept is available at https://github.com/JohnLato/meta-th, which, although not very sophisticated, shows one general technique that even provides a modicum of type safety. Template Haskell expressions are build using the Meta type, which can then be compiled and loaded into a usable function.
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wall #-}
module Data.Meta.Meta (
-- * Meta type
Meta (..)
-- * Functions
, metaCompile
) where
import Language.Haskell.TH
import Data.Typeable as Typ
import Control.Exception (bracket)
import System.Plugins -- from plugins
import System.IO
import System.Directory
newtype Meta a = Meta { unMeta :: ExpQ }
-- | Super-dodgy for the moment, the Meta type should register the
-- imports it needs.
metaCompile :: forall a. Typeable a => Meta a -> IO (Either String a)
metaCompile (Meta expr) = do
expr' <- runQ expr
-- pretty-print the TH expression as source code to be compiled at
-- run-time
let interpStr = pprint expr'
typeTypeRep = Typ.typeOf (undefined :: a)
let opener = do
(tfile, h) <- openTempFile "." "fooTmpFile.hs"
hPutStr h (unlines
[ "module TempMod where"
, "import Prelude"
, "import Language.Haskell.TH"
, "import GHC.Num"
, "import GHC.Base"
, ""
, "myFunc :: " ++ show typeTypeRep
, "myFunc = " ++ interpStr] )
hFlush h
hClose h
return tfile
bracket opener removeFile $ \tfile -> do
res <- make tfile ["-O2", "-ddump-simpl"]
let ofile = case res of
MakeSuccess _ fp -> fp
MakeFailure errs -> error $ show errs
print $ "loading from: " ++ show ofile
r2 <- load (ofile) [] [] "myFunc"
print "loaded"
case r2 of
LoadFailure er -> return (Left (show er))
LoadSuccess _ (fn :: a) -> return $ Right fn
This function takes an ExpQ, and first runs it in IO to create a plain Exp. The Exp is then pretty-printed into source code, which is compiled and loaded at run-time. In practice, I've found that one of the more difficult obstacles is specifying the correct imports in the generated TH code.
From what I understand you want to create and run a code at runtime which I think you can do using GHC API but I am not very sure of the scope of what you can achieve. If you want something like hot code swapping you can look at the package hotswap.
I want to do something like this in Haskell, but the compiler is not letting me.
Is there any way to accomplish this task?
-- both modules export function named "hello"
-- and I want to run it in every module
import qualified MyMod as M1
import qualified MyAnotherMod as M2
runmodules = map (\m -> m.hello) [M1, M2]
Modules in Haskell are not even remotely first-class entities in the ways this would require, I'm afraid.
However, as bzn commented, Template Haskell can be used for problems like this. The result can be a bit clumsy, but if you really need some quick metaprogramming hacks it's not a bad choice. I'm not really an expert with TH, but what you want is pretty simple, with one catch: Neither "ambiguous identifiers" nor "module names" can be captured or quoted in any way, as far as I know, so you'll have to put them in strings given as arguments to the TH function.
Here's a quick and dirty, minimal example:
{-# LANGUAGE TemplateHaskell #-}
module MapModuleTH where
import Language.Haskell.TH
mapQual :: [String] -> String -> ExpQ
mapQual ms n = listE $ map (\m -> varE . mkName $ m ++ "." ++ n) ms
mapMQual :: [String] -> String -> ExpQ
mapMQual ms n = appE (varE 'sequence) $ listE $ map (\m -> varE . mkName $ m ++ "." ++ n) ms
You phrased things as "running the function" which sounds more like doing a bunch of IO actions, not just collecting a list of stuff, so I added a variant that also sequences the result.
Note that, despite the use of strings here, this is still statically typed--if the qualified names don't exist, or the types don't match up, you'll get the expected compile-time error just as if you'd written everything out by hand.
Here's a quick example of using it. Given the following:
{-# LANGUAGE TemplateHaskell #-}
module MapModule where
import MapModuleTH
import qualified Test1 as T1
import qualified Test2 as T2
tests = do xs <- $(mapMQual ["T1", "T2"] "test")
putStrLn $ "Count: " ++ show (length xs)
Assuming the other modules are there and define test, then in GHCi we can see:
> tests
Test 1
Test 2
Count: 2
I don't think you can quote a qualified name prefix like that in template haskell, and the hello identifier isn't in scope, so you might have to fall back to programming with strings.
module ModuleParamsTH where
import Language.Haskell.TH
getAll :: String -> [String] -> ExpQ
getAll valueName moduleNames =
listE $ map (varE . mkName . (++ suffix)) moduleNames
where suffix = "." ++ valueName
which can then be used like so,
{-# LANGUAGE TemplateHaskell #-}
import ModuleParamsTH
import qualified ModuleParamsM1 as M1
import qualified ModuleParamsM2 as M2
runmodules = $(getAll "hello" ["M1", "M2"])
However, I would not do all this. You could just write [M1.hello, M2.hello] or use a type class to abstract over implementations.
Modules aren't values in Haskell. Therefore that isn't possible. What do you want to achieve?
I'm trying to become familiar with Template Haskell, and to my surprise the code below compiles under ghc (version 6.10.4).
main = do
let
y = [| "hello" + 1 |]
putStr ""
This suggest to me that there's no typechecking inside quasi-quotes. This is not what I'd have expected after reading the original paper on Template Haskell. Moreover the following program does not compile.
main = do
let
y = [| "hello" && True |]
putStr ""
What's going on here?
It looks like GHC does type check all quotations but assumes that all generated instance constraints can be satisfied.
In this code:
main = do
let
y = [| "hello" + 1 |]
putStr ""
The y bracket is typeable under the assumption that we have a Num String instance. Since GHC can't say for sure that you won't introduce such an instance before y is spliced in, it doesn't give a type error.
In this code:
main = do
let
y = [| "hello" && True |]
putStr ""
There is no way that y can ever be spliced in successfully, no matter what instance environment you set up.
This is just one example of how Template Haskell's typechecking mechanism is too lenient -- further examples are discussed in Simon PJ's blog post at http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal, where he proposes a change to not type check any quotations at all.
Template Haskell has two main operations:
lifting: [| |]
splicing $( )
When you wrap something in the Oxford brackets, you delay its type checking (and evaluation), and instead build an AST fragment that will be type checked when it is spliced back in.
The AST that is built can be observed:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
main = print =<< runQ [| "hello" + 1 |]
Running this program (or typing the bracket expression into GHCi), and we get a well-formed AST, but one that is not type correct if treated as a Haskell fragment:
InfixE (Just (LitE (StringL "hello"))) (VarE GHC.Num.+) (Just (LitE (IntegerL 1)))
Now when we try to actually splice it, type checking happens:
*Main> :t [| "hello" + 1 |]
[| "hello" + 1 |] :: Q Exp
*Main> $( [| "hello" + 1 |] )
<interactive>:1:4:
No instance for (Num [Char])
arising from the literal `1'
As we expect. So, yes, TH expressions are type checked, but at a late point, when spliced back into a program.