I would like to paste in a large number constant into my Haskell code, and for readability I would like to have it formatted over several lines instead of one line.
Is this possible?
This is a possible approach. I'm not completely sure about it, though. There might be an easier way.
largeConstant :: Integer
largeConstant = read $
"12345" ++
"12345" ++
"12345"
Alternatively, we could use multiline string literals, even though they are not very commonly used in Haskell.
largeConstant :: Integer
largeConstant = read
"12345\
\12345\
\12345"
Enabling CPP is also an option, but seems a bit overkill.
largeConstant = 12345\
12345\
12345
You could make a quasiquoter. Might even want to upload it to hackage:
module X where
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Data.Char
iQQ :: QuasiQuoter
iQQ = QuasiQuoter {
quoteExp = return . LitE . IntegerL . read . filter isDigit,
quotePat = \_ -> fail "illegal integer QuasiQuote \
\(allowed as expression only, used as a pattern)",
quoteType = \_ -> fail "illegal integer QuasiQuote \
\(allowed as expression only, used as a type)",
quoteDec = \_ -> fail "illegal integer QuasiQuote \
\(allowed as expression only, used as a declaration)"
}
And the use:
{-# LANGUAGE QuasiQuotes #-}
import X
value = [iQQ|123
456|]
Resulting in:
Ok, two modules loaded.
*Main> value
123456
Or a larger number:
value = [iQQ|
44444444444444444444444444444444444444444444444444444444444444444444444444444444
45555555555555555555555555555555555555555555555555555555555555555555555555555555
66666666666666666666666666666666666666666666666666666666666666666666666666666666
|]
And in GHCi:
Ok, two modules loaded.
*Main> value
444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666
Related
I'd like to get both the string and value of arbitrary Haskell code. For example:
f (1+1) -> (2,"1+1")
The reason I want to do this is because I'm writing a programming language and I'd like to provide an option to interpret the code (for fast running, i.e. scripting) or compile it to Haskell code (for efficient runtime). So for each builtin I only want to provide the implementation once. That is I don't want to say
plusop = ((+),"(+)")
I have some ideas involving reading the raw haskell source or a separate script that generates a compiler, but these seem much less elegant that what would be done if this question is possible.
It looks like QuasiQuotation could make this possible, but I can't figure out how to get the Haskell value of the expression if I use it (I can only get the String).
Is it possible? How can it be done?
I don't know exactly what you want to do, but here's an example of using Template Haskell to do something similar to your example:
-- TH.hs
{-# LANGUAGE TemplateHaskell #-}
module TH where
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Ppr
showAndRun :: Q Exp -> Q Exp
showAndRun m = do
x <- m
let s = pprint x
[| ($m, s) |]
-- Main.hs
{-# LANGUAGE TemplateHaskell #-}
import TH
main :: IO ()
main = print $(showAndRun [| 1 + 1 |])
$ runhaskell Main.hs
(2,"1 GHC.Num.+ 1")
I don't know how to pretty print the expression without the qualified GHC.Num prefix. You could try copying the implementation of Language.Haskell.TH.Ppr and change it in the necessary places. Or the easiest is perhaps just a post-processing step where you strip each word that starts with a capital letter and ends in a ..
I need to communicate some information from compile scripts into Template Haskell. Currently the compile scripts keep the information in the system environment, so I just read it using System.Environment.getEnvironment wrapped in runIO. Is there a better way, such as passing some arguments to ghc (similar to -D... for the C pre-processor), or perhaps something specifically designed for this purpose in TH?
Since so many people are interested in the question, I'll add my current approach, perhaps somebody will find it useful. Probably the best way would be if TH allowed to read -D parameters on GHC's command line, but it seems nothing like this is currently implemented.
A simple module allows TH to read compile-time environment. A helper function also allows to read files; for example read the path of a configuration file from the environment and then read the file.
{-# LANGUAGE TemplateHaskell #-}
module THEnv
(
-- * Compile-time configuration
lookupCompileEnv
, lookupCompileEnvExp
, getCompileEnv
, getCompileEnvExp
, fileAsString
) where
import Control.Monad
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Language.Haskell.TH
import Language.Haskell.TH.Syntax (Lift(..))
import System.Environment (getEnvironment)
-- Functions that work with compile-time configuration
-- | Looks up a compile-time environment variable.
lookupCompileEnv :: String -> Q (Maybe String)
lookupCompileEnv key = lookup key `liftM` runIO getEnvironment
-- | Looks up a compile-time environment variable. The result is a TH
-- expression of type #Maybe String#.
lookupCompileEnvExp :: String -> Q Exp
lookupCompileEnvExp = (`sigE` [t| Maybe String |]) . lift <=< lookupCompileEnv
-- We need to explicly type the result so that things like `print Nothing`
-- work.
-- | Looks up an compile-time environment variable and fail, if it's not
-- present.
getCompileEnv :: String -> Q String
getCompileEnv key =
lookupCompileEnv key >>=
maybe (fail $ "Environment variable " ++ key ++ " not defined") return
-- | Looks up an compile-time environment variable and fail, if it's not
-- present. The result is a TH expression of type #String#.
getCompileEnvExp :: String -> Q Exp
getCompileEnvExp = lift <=< getCompileEnv
-- | Loads the content of a file as a string constant expression.
-- The given path is relative to the source directory.
fileAsString :: FilePath -> Q Exp
fileAsString = do
-- addDependentFile path -- works only with template-haskell >= 2.7
stringE . T.unpack . T.strip <=< runIO . T.readFile
It can be used like this:
{-# LANGUAGE TemplateHaskell #-}
import THEnv
main = print $( lookupCompileEnvExp "DEBUG" )
Then:
runhaskell Main.hs prints Nothing;
DEBUG="yes" runhaskell Main.hs prints Just "yes".
It looks like what you are trying to do here, The -D option in ghc seems to define a compile time variable.
Here, on the same subject is a question that seems to also answer the other part of your question.
From what I can tell, to do conditional compilation, you do something like:
#ifdef MACRO_NAME
//Do stuff here
#endif
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?
So, I could accomplish this by using 'topLevelSomething and removing the last token after ., or I could use moduleName 'something but that returns a Maybe...
Is there a more straightforward way to get the module name of the current context?
So, given the code:
module My.Module.Blah where
test = magicHere
What goes in that magicHere spot such that test = "My.Module.Blah" ?
I thought this was a nice question, so I figured out the answer using Template Haskell:
{-# LANGUAGE TemplateHaskell #-}
module A.B.C where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
e :: String
e = $(fmap loc_module qLocation >>= \mod -> return (LitE (StringL mod) ))
main = print e
There's a rather roundabout way to get the current module name using Typeable.
module My.Module.Blah where
import Data.Typeable
data T = T deriving Typeable
test = init $ init $ show $ typeOf T
Great answers. We ended up doing it this way as it seemed a little cleaner.
moduleOf 'someTopLevelThingInModule
moduleOf :: Language.Haskell.TH.Syntax.Name -> String
moduleOf = dropLastToken . show
dropLastToken :: String -> String
dropLastToken = reverse . tail . dropWhile (/= '.') . reverse
Actually I have some formula like "x + y", which is a String.
I managed to replace the x/y variable with specific values like "1.2", which is still String type.
Now I have expression like "1 + 2".
So the problem is how to evaluate a expression of a string type and get the result.
ps: I wanna sth like read, that can directly convert the whole string expression instead of handling the operator (+/-,etc) case by case. Is that possible?
Your question leaves a lot of room for interpretation. I'm taking a guess you aren't accustom to building a whole pipeline of lexing, parsing, maybe type checking, and evaluating. The long answer would involve you defining what language you wish to evaluate (Just integers with '+', perhaps all rationals with '+', '-' '*', '/', or even a larger language?) and perform each of the above steps for that language.
The short answer is: to evaluate Haskell expressions, which includes the basic math operators you're probably talking about, just use the "hint" package:
$ cabal install hint
...
$ ghci
> import Language.Haskell.Interpreter
> runInterpreter $ setImports ["Prelude"] >> eval "3 + 5"
Right "8"
Yay!
Might be worth reading the Parsec section of Real World Haskell. You could parse it into an expression tree and then substitute the values in. As you use Parsec you'd build up an expression tree using types (very roughly, I'm sure I've made some mistakes which I'll edit in fixes for as and when people point them out!) like that below.
data Op = Plus | Minus
data Term = Variable String
| Value Int
data Expression = Expr Expression Op Expression
| Term
Then 1 + 2 would be (Expr (Variable "x") Plus (Variable "y")) and you could apply the appropriate substitutions.
To get the result, I guess you could right a simple function evaluate :: Map String Int -> Expression -> Either ErrorMessage Int which would apply the bindings in the map and then calculate the result if possible.
Well I've been banging my head against hint but I give up for now. I know hint can do this but I'm not sure how. [edit] See TomMD's answer for how to set imports up for hint. [/edit]
import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError)
main = do let resIO = eval "3" :: Interpreter String
res <- runInterpreter resIO
print res
This uninterestingly produces Right "3" as the result. I tried the following variants, only to run into baffling errors:
... eval "3 + 3" ....
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"])
The + operator isn't in scope??? wtf...
import Language.Haskell.Interpreter (interpret, as, runInterpreter, Interpreter)
main = do let resIO = interpret "3" (as :: Int) :: Interpreter Int
res <- runInterpreter resIO
print res
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: type constructor or class 'Int'")])
The Int class isn't in scope??? ugh...
I invite those more knowledgeable than me to expound on the finer details of hint.
The accepted answer shows a minimal example of using the hint, but it lacks couple of things:
How to evaluate using bindings like let x = 1 in x + 1.
How to handle exceptions, specifically divide by zero.
Here is a more complete example:
import qualified Control.DeepSeq as DS
import Control.Exception (ArithException (..))
import qualified Control.Exception as Ex
import qualified Control.Monad as M
import qualified Data.Either as E
import qualified Language.Haskell.Interpreter as I
evalExpr :: String -> [(String, Integer)] -> IO (Maybe Integer)
evalExpr expr a = Ex.handle handler $ do
i <- I.runInterpreter $ do
I.setImports ["Prelude"]
-- let var = value works too
let stmts = map (\(var, val) -> var ++ " <- return " ++ show val) a
M.forM_ stmts $ \s -> do
I.runStmt s
I.interpret expr (I.as :: Integer)
-- without force, exception is not caught
(Ex.evaluate . DS.force) (E.either (const Nothing) Just i)
where
handler :: ArithException -> IO (Maybe Integer)
handler DivideByZero = return Nothing
handler ex = error $ show ex