git.iko.soy/haskell-generate
on master help sign in
.travis.yml+6−4
since splitsnapshots
unifiedsplit
@@ -1,17 +1,19 @@
1env:
1env:
2 - GHCVER=7.4.2 CABALVER=1.16
2 - GHCVER=7.4.2 CABALVER=1.16
3 - GHCVER=7.6.3 CABALVER=1.18
3 - GHCVER=7.6.3 CABALVER=1.18
4+ - GHCVER=7.8.3 CABALVER=1.20
5+ - GHCVER=7.10.2 CABALVER=1.22
4− - GHCVER=head CABALVER=1.18
6+ - GHCVER=head CABALVER=1.22
5
7
6before_install:
8before_install:
7 - sudo add-apt-repository -y ppa:hvr/ghc
9 - sudo add-apt-repository -y ppa:hvr/ghc
8 - sudo apt-get update
10 - sudo apt-get update
9 - sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER hlint
11 - sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER hlint
12+ - cabal-$CABALVER update
10 - cabal-$CABALVER install happy -j
13 - cabal-$CABALVER install happy -j
11 - export PATH=/opt/ghc/$GHCVER/bin:~/.cabal/bin:$PATH
14 - export PATH=/opt/ghc/$GHCVER/bin:~/.cabal/bin:$PATH
12
15
13install:
16install:
14− - cabal-$CABALVER update
15 - cabal-$CABALVER install --only-dependencies --enable-tests --enable-benchmarks -j
17 - cabal-$CABALVER install --only-dependencies --enable-tests --enable-benchmarks -j
16
18
17script:
19script:
@@ -20,5 +22,5 @@ script:
20
22
21matrix:
23matrix:
22 allow_failures:
24 allow_failures:
23− - env: GHCVER=head CABALVER=1.18
25+ - env: GHCVER=head CABALVER=1.22
24− fast_finish: true
26+ fast_finish: true
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright 2013 Benno Fünfstück
1+Copyright 2013-2015 Benno Fünfstück
2
2
3All rights reserved.
3All rights reserved.
4
4
README.md+99−1
@@ -1,6 +1,104 @@
1haskell-generate
1haskell-generate
2−====================
2+================
3
3
4[![Build Status](https://secure.travis-ci.org/bennofs/haskell-generate.png?branch=master)](http://travis-ci.org/bennofs/haskell-generate)
4[![Build Status](https://secure.travis-ci.org/bennofs/haskell-generate.png?branch=master)](http://travis-ci.org/bennofs/haskell-generate)
5
5
6+## Introduction
6
7
8+If you want to generate haskell source code, you could build up haskell-src-exts AST and then pretty print it. But that's easy to screw up, because haskell-src-exts doesn't include tag it's AST with a type. This library aims to fill the gap, adding type information to haskell-src-exts expressions and also managing imports for you.
9+
10+## Getting started
11+
12+First, you need to import this library:
13+
14+```haskell
15+import Language.Haskell.Generate
16+```
17+
18+This module reexports `Language.Haskell.Exts.Syntax`, because haskell-generate builds on top of that.
19+
20+There are two main types in haskell-generate. The first is the monad `Generate` and the type alias `ExpG`. The `Generate` monad is used to track required imports. It also allows to generate unique names. `ExpG t` is just an action in the `Generate` monad that returns an expression of type `t`.
21+
22+How do you build expressions? There is a number of predefined expressions for the functions in the
23+Prelude. This allows you to just use these and combine them to new expressions. For example, let's define a expression that reads a file called "names":
24+
25+```haskell
26+readNamesFile' :: ExpG (IO String)
27+readNamesFile' = readFile' <>$ expr "names"
28+```
29+
30+Here we use `(<>$)` to apply the `readFile'` expression to the string `names`. `readFile'` is one of the expressions already provided by haskell-generate. All expressions that are provided by haskell-generate end with an apostrophe. You can find more of them in the module `Language.Haskell.Generate.PreludeDef`. The `expr` function is used to lift the string `names` into an expression of type `ExpG String`.
31+
32+Now that we have an expression, we need to bind it to a name in a module. For this job, we use another monad, the `ModuleM` monad. It allows you to bind expressions to names and then generate
33+a module with those names.
34+
35+Here's how we generate our module:
36+
37+```haskell
38+myModule :: ModuleG
39+myModule = do
40+ d <- addDecl (Ident "main") $ applyE2 bind' readNamesFile' putStrLn'
41+ return $ Just [exportFun d]
42+```
43+
44+`ModuleG` is again a type synonym for an action in the `ModuleM` monad. It must either return Nothing (which omits the export list) or an export list. In this case, we export the "main" function, which we previously defined using `addDecl`.
45+
46+The only thing left to do is to generate the actual source code for the module, for which we
47+use the `generateModule` function, which takes the module name as an argument:
48+
49+```haskell
50+main :: IO ()
51+main = putStrLn $ generateModule myModule "Main"
52+```
53+
54+If you run the program, you'll get the following output:
55+
56+```haskell
57+module Main (main) where
58+import qualified GHC.Base
59+import qualified System.IO
60+main
61+ = (GHC.Base.>>=) (System.IO.readFile ['n', 'a', 'm', 'e', 's'])
62+ System.IO.putStrLn
63+```
64+
65+If you run this code, you'll get the contents of the "names" file. The code is a bit ugly and uses
66+qualified imports to avoid name clashes, but it works.
67+
68+## Importing functions
69+
70+Until now, we've only used the predefined expressions from `Language.Haskell.Generate.PreludeDef`, but often you'll want to use definitions from other modules that you might want to use.
71+
72+You can do that using the `useValue` from haskell-generate. Let's look at the type of `useValue`:
73+
74+```haskell
75+useValue :: String -> Name -> ExpG t
76+```
77+
78+`useValue` takes a module name in which the function is defined and the name of the function. It returns an expression of any type you which. This function is unsafe, because it cannot check that the returned type is actually the type of the function. That's why you usually given `useValue` an explicit type signature.
79+
80+For example, suppose we want to use the function `permutations` from Data.List. We write the following definition for it:
81+
82+```haskell
83+permutations' :: ExpG ([a] -> [[a]]) -- Here we given an explicit type for permutations'. This is not checked, so make sure it's actually right!
84+permutations' = useValue "Data.List" (Ident "permutations") -- "permutations" is an identifier, not a symbol, so we use the "Ident" constructor.
85+```
86+
87+## Using TH to automagically import functions
88+
89+If the function you want to import is already available at compile time, you can use the template haskell code from `Language.Haskell.Generate.TH` to generate the expression definitions. This is the approach we use for the Prelude, as an example.
90+
91+Using the example from the previous section, we could also import the `permutations` function like this:
92+
93+```haskell
94+-- at the top of the file:
95+{-# LANGUAGE TemplateHaskell #-} -- Enable template haskell
96+import Data.List (permutations) -- The function needs to be available at compile time
97+
98+declareFunction 'permutations -- This generates the same code as above, but is more type-safe because you don't have to specify the type yourself.
99+```
100+
101+
102+## Contributing
103+
104+If you have an idea, a question or a bug report, open an issue on github. You can also find me on freenode in the #haskell channel, my nick is bennofs.
haskell-generate.cabal+11−7
@@ -1,5 +1,5 @@
1name: haskell-generate
1name: haskell-generate
2−version: 0.1
2+version: 0.2.4
3license: BSD3
3license: BSD3
4category: Code Generation, Language
4category: Code Generation, Language
5cabal-version: >= 1.10
5cabal-version: >= 1.10
@@ -9,9 +9,13 @@ maintainer: Benno Fünfstück <benno.fuenfstueck@gmail.com>
9stability: experimental
9stability: experimental
10homepage: http://github.com/bennofs/haskell-generate/
10homepage: http://github.com/bennofs/haskell-generate/
11bug-reports: http://github.com/bennofs/haskell-generate/issues
11bug-reports: http://github.com/bennofs/haskell-generate/issues
12−copyright: Copyright (C) 2013 Benno Fünfstück
12+copyright: Copyright (C) 2013-2015 Benno Fünfstück
13−synopsis: haskell-generate
13+synopsis: Typesafe generation of haskell source code
14−description: haskell-generate
14+description:
15+ This library provides an interface to generate haskell source code, verifying at compile time
16+ that the resulting code typechecks.
17+ See <https://github.com/bennofs/haskell-generate haskell-generate> for an
18+ introduction explaining how to use the library.
15build-type: Custom
19build-type: Custom
16
20
17extra-source-files:
21extra-source-files:
@@ -37,9 +41,11 @@ library
37 , template-haskell
41 , template-haskell
38 exposed-modules:
42 exposed-modules:
39 Language.Haskell.Generate
43 Language.Haskell.Generate
40− Language.Haskell.Generate.Base
44+ Language.Haskell.Generate.Monad
45+ Language.Haskell.Generate.Expression
41 Language.Haskell.Generate.TH
46 Language.Haskell.Generate.TH
42 Language.Haskell.Generate.PreludeDef
47 Language.Haskell.Generate.PreludeDef
48+ other-extensions: TemplateHaskell
43
49
44test-suite doctests
50test-suite doctests
45 type: exitcode-stdio-1.0
51 type: exitcode-stdio-1.0
@@ -51,6 +57,4 @@ test-suite doctests
51 , doctest >= 0.9.1
57 , doctest >= 0.9.1
52 , filepath
58 , filepath
53 ghc-options: -Wall -threaded
59 ghc-options: -Wall -threaded
54− if impl(ghc<7.6.1)
55− ghc-options: -Werror
56 hs-source-dirs: tests
60 hs-source-dirs: tests
src/Language/Haskell/Generate.hs+2−1
@@ -2,5 +2,6 @@ module Language.Haskell.Generate
2 ( module X
2 ( module X
3 ) where
3 ) where
4
4
5−import Language.Haskell.Generate.Base as X
5+import Language.Haskell.Exts.Syntax as X
6+import Language.Haskell.Generate.Monad as X
6import Language.Haskell.Generate.PreludeDef as X
7import Language.Haskell.Generate.PreludeDef as X
src/Language/Haskell/Generate/Expression.hsnew file+12
@@ -0,0 +1,12 @@
1+module Language.Haskell.Generate.Expression
2+ ( Expression(..)
3+ , app
4+ ) where
5+
6+import Language.Haskell.Exts.Syntax
7+
8+newtype Expression t = Expression { runExpression :: Exp }
9+
10+app :: Expression (a -> b) -> Expression a -> Expression b
11+app (Expression a) (Expression b) = Expression $ App a b
12+
src/Language/Haskell/Generate/Base.hs → src/Language/Haskell/Generate/Monad.hsrenamed+93−51
@@ -3,9 +3,11 @@
3{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE UndecidableInstances #-}
4{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE CPP #-}
6−module Language.Haskell.Generate.Base
7+module Language.Haskell.Generate.Monad
7− ( ExpM(..), ExpG, ExpType
8+ ( Generate(..), ExpG
8− , runExpM, newName
9+ , runGenerate, newName
10+ , returnE
9 , useValue, useCon, useVar
11 , useValue, useCon, useVar
10 , caseE
12 , caseE
11 , applyE, applyE2, applyE3, applyE4, applyE5, applyE6
13 , applyE, applyE2, applyE3, applyE4, applyE5, applyE6
@@ -19,6 +21,7 @@ module Language.Haskell.Generate.Base
19 , addDecl
21 , addDecl
20 , runModuleM
22 , runModuleM
21 , generateModule
23 , generateModule
24+ , generateExp
22 )
25 )
23 where
26 where
24
27
@@ -31,32 +34,44 @@ import qualified Data.Set as S
31import Language.Haskell.Exts.Pretty
34import Language.Haskell.Exts.Pretty
32import Language.Haskell.Exts.SrcLoc
35import Language.Haskell.Exts.SrcLoc
33import Language.Haskell.Exts.Syntax
36import Language.Haskell.Exts.Syntax
37+import Language.Haskell.Generate.Expression
38+
39+import Prelude
34
40
35--------------------------------------------------------------------------------
41--------------------------------------------------------------------------------
36-- Generate expressions
42-- Generate expressions
37
43
38−-- | A ExpM is a monad used to track the imports that are needed for a given expression. Usually, you don't have to use
44+-- | This monad keeps track of a counter for generating unique names and the set of modules
39−-- this type directly, but use combinators to combine several ExpM into bigger expressions. The t type parameter tracks
45+-- that are needed for the expression.
40−-- the type of the expression, so you don't accidently build expression that don't type check.
41−newtype ExpM t a = ExpM { unExpM :: StateT Integer (Writer (S.Set ModuleName)) a } deriving (Functor, Applicative, Monad)
46+newtype Generate a = Generate { unGenerate :: StateT Integer (Writer (S.Set ModuleName)) a } deriving (Functor, Applicative, Monad)
47+
48+-- | Extract the set of modules and the value from a Generate action.
49+runGenerate :: Generate a -> (a, S.Set ModuleName)
50+runGenerate (Generate a) = runWriter $ evalStateT a 0
42
51
43−-- | The ExpG type is a ExpM computation that returns an expression. Usually, this is the end result of a function generating
52+-- | This is a type alias for a Generate action that returns an expression of type 't'.
44−-- a haskell expression
45−type ExpG t = ExpM t Exp
53+type ExpG t = Generate (Expression t)
46
54
47−-- | Evaluate a ExpM action, returning the needed modules and the value.
55+-- | Use a haskell-src-exts Exp as the result of a Generate action.
48−runExpM :: ExpM t a -> (a, S.Set ModuleName)
56+returnE :: Exp -> ExpG t
49−runExpM (ExpM expt) = runWriter $ evalStateT expt 0
57+returnE = return . Expression
50
58
51−unsafeCoerceE :: ExpM t a -> ExpM t' a
59+-- | Pretty print the expression generated by a given action.
52−unsafeCoerceE (ExpM x) = ExpM x
60+generateExp :: ExpG t -> String
61+generateExp = prettyPrint . runExpression . fst . runGenerate
53
62
54-- | Generate a case expression.
63-- | Generate a case expression.
55caseE :: ExpG x -> [(Pat, ExpG t)] -> ExpG t
64caseE :: ExpG x -> [(Pat, ExpG t)] -> ExpG t
56caseE v alt = do
65caseE v alt = do
57− v' <- unsafeCoerceE v
66+ v' <- v
67+#if MIN_VERSION_haskell_src_exts(1,17,0)
68+ alt' <- mapM (\(p,a) -> fmap (\a' -> Alt noLoc p (UnGuardedRhs $ runExpression a') Nothing) a) alt
69+#elif MIN_VERSION_haskell_src_exts(1,16,0)
70+ alt' <- mapM (\(p,a) -> fmap (\a' -> Alt noLoc p (UnGuardedRhs $ runExpression a') (BDecls [])) a) alt
71+#else
58− alt' <- mapM (\(p,a) -> fmap (\a' -> Alt noLoc p (UnGuardedAlt a') (BDecls [])) a) alt
72+ alt' <- mapM (\(p,a) -> fmap (\a' -> Alt noLoc p (UnGuardedAlt $ runExpression a') (BDecls [])) a) alt
73+#endif
59− return $ Case v' alt'
74+ return $ Expression $ Case (runExpression v') alt'
60
75
61-- | Import a function from a module. This function is polymorphic in the type of the resulting expression,
76-- | Import a function from a module. This function is polymorphic in the type of the resulting expression,
62-- you should probably only use this function to define type-restricted specializations.
77-- you should probably only use this function to define type-restricted specializations.
@@ -67,32 +82,37 @@ caseE v alt = do
67-- > addInt = useValue "Prelude" $ Symbol "+"
82-- > addInt = useValue "Prelude" $ Symbol "+"
68--
83--
69useValue :: String -> Name -> ExpG a
84useValue :: String -> Name -> ExpG a
70−useValue md name = ExpM $ do
85+useValue md name = Generate $ do
71 lift $ tell $ S.singleton $ ModuleName md
86 lift $ tell $ S.singleton $ ModuleName md
72− return $ Var $ Qual (ModuleName md) name
87+ return $ Expression $ Var $ Qual (ModuleName md) name
73
88
74-- | Import a value constructor from a module. Returns the qualified name of the constructor.
89-- | Import a value constructor from a module. Returns the qualified name of the constructor.
75−useCon :: String -> Name -> ExpM t QName
90+useCon :: String -> Name -> Generate QName
76−useCon md name = ExpM $ do
91+useCon md name = Generate $ do
77 lift $ tell $ S.singleton $ ModuleName md
92 lift $ tell $ S.singleton $ ModuleName md
78 return $ Qual (ModuleName md) name
93 return $ Qual (ModuleName md) name
79
94
80-- | Use the value of a variable with the given name.
95-- | Use the value of a variable with the given name.
81useVar :: Name -> ExpG t
96useVar :: Name -> ExpG t
82−useVar name = return $ Var $ UnQual name
97+useVar name = return $ Expression $ Var $ UnQual name
83
98
84-- | Generate a new unique variable name with the given prefix. Note that this new variable name
99-- | Generate a new unique variable name with the given prefix. Note that this new variable name
85-- is only unique relative to other variable names generated by this function.
100-- is only unique relative to other variable names generated by this function.
86−newName :: String -> ExpM t Name
101+newName :: String -> Generate Name
87−newName pref = ExpM $ do
102+newName pref = Generate $ do
88 i <- get <* modify succ
103 i <- get <* modify succ
89 return $ Ident $ pref ++ show i
104 return $ Ident $ pref ++ show i
90
105
91−-- | This type family can be used to get the type associated with some expression.
106+-- | Generate a expression from a haskell value. This can for example be used to create lambdas:
92−type family ExpType a :: *
107+--
93−type instance ExpType (ExpM t a) = t
108+-- >>> putStrLn $ generateExp $ expr (\x f -> f <>$ x)
94−
109+-- \ pvar_0 -> \ pvar_1 -> pvar_1 pvar_0
95−-- | Generate a expression from a haskell value.
110+--
111+-- Or string literals:
112+--
113+-- >>> putStrLn $ generateExp $ expr "I'm a string!"
114+-- ['I', '\'', 'm', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '!']
115+--
96class GenExp t where
116class GenExp t where
97 type GenExpType t :: *
117 type GenExpType t :: *
98
118
@@ -103,36 +123,41 @@ instance GenExp (ExpG a) where
103 type GenExpType (ExpG a) = a
123 type GenExpType (ExpG a) = a
104 expr = id
124 expr = id
105
125
126+instance GenExp (Expression t) where
127+ type GenExpType (Expression t) = t
128+ expr = return
129+
106instance GenExp Char where
130instance GenExp Char where
107 type GenExpType Char = Char
131 type GenExpType Char = Char
108− expr = return . Lit . Char
132+ expr = return . Expression . Lit . Char
109
133
110instance GenExp Integer where
134instance GenExp Integer where
111 type GenExpType Integer = Integer
135 type GenExpType Integer = Integer
112− expr = return . Lit . Int
136+ expr = return . Expression . Lit . Int
113
137
114instance GenExp Rational where
138instance GenExp Rational where
115 type GenExpType Rational = Rational
139 type GenExpType Rational = Rational
116− expr = return . Lit . Frac
140+ expr = return . Expression . Lit . Frac
117
141
118instance GenExp a => GenExp [a] where
142instance GenExp a => GenExp [a] where
119 type GenExpType [a] = [GenExpType a]
143 type GenExpType [a] = [GenExpType a]
120− expr = ExpM . fmap List . mapM (unExpM . expr)
144+ expr = Generate . fmap (Expression . List . map runExpression) . mapM (unGenerate . expr)
121
145
122instance GenExp x => GenExp (ExpG a -> x) where
146instance GenExp x => GenExp (ExpG a -> x) where
123 type GenExpType (ExpG a -> x) = a -> GenExpType x
147 type GenExpType (ExpG a -> x) = a -> GenExpType x
124 expr f = do
148 expr f = do
125 pvarName <- newName "pvar_"
149 pvarName <- newName "pvar_"
126− body <- unsafeCoerceE $ expr $ f $ return $ Var $ UnQual pvarName
150+ body <- expr $ f $ return $ Expression $ Var $ UnQual pvarName
127− return $ Lambda noLoc [PVar pvarName] body
151+ return $ Expression $ Lambda noLoc [PVar pvarName] $ runExpression body
128
152
129--------------------------------------------------------------------------------
153--------------------------------------------------------------------------------
130-- Apply functions
154-- Apply functions
131
155
132-- | Apply a function in a haskell expression to a value.
156-- | Apply a function in a haskell expression to a value.
133applyE :: ExpG (a -> b) -> ExpG a -> ExpG b
157applyE :: ExpG (a -> b) -> ExpG a -> ExpG b
134−applyE a b = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b]
158+applyE a b = wrap $ liftM (foldl1 App) $ sequence [unwrap a, unwrap b]
135− where ce = unsafeCoerceE
159+ where wrap = fmap Expression
160+ unwrap = fmap runExpression
136
161
137-- | Operator for 'applyE'.
162-- | Operator for 'applyE'.
138(<>$) :: ExpG (a -> b) -> ExpG a -> ExpG b
163(<>$) :: ExpG (a -> b) -> ExpG a -> ExpG b
@@ -142,28 +167,33 @@ infixl 1 <>$
142
167
143-- | ApplyE for 2 arguments
168-- | ApplyE for 2 arguments
144applyE2 :: ExpG (a -> b -> c) -> ExpG a -> ExpG b -> ExpG c
169applyE2 :: ExpG (a -> b -> c) -> ExpG a -> ExpG b -> ExpG c
145−applyE2 a b c = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b,ce c]
170+applyE2 a b c = wrap $ liftM (foldl1 App) $ sequence [unwrap a,unwrap b,unwrap c]
146− where ce = unsafeCoerceE
171+ where wrap = fmap Expression
172+ unwrap = fmap runExpression
147
173
148-- | Apply a function to 3 arguments
174-- | Apply a function to 3 arguments
149applyE3 :: ExpG (a -> b -> c -> d) -> ExpG a -> ExpG b -> ExpG c -> ExpG d
175applyE3 :: ExpG (a -> b -> c -> d) -> ExpG a -> ExpG b -> ExpG c -> ExpG d
150−applyE3 a b c d = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b,ce c,ce d]
176+applyE3 a b c d = wrap $ liftM (foldl1 App) $ sequence [unwrap a,unwrap b,unwrap c,unwrap d]
151− where ce = unsafeCoerceE
177+ where wrap = fmap Expression
178+ unwrap = fmap runExpression
152
179
153-- | Apply a function to 4 arguments
180-- | Apply a function to 4 arguments
154applyE4 :: ExpG (a -> b -> c -> d -> e) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e
181applyE4 :: ExpG (a -> b -> c -> d -> e) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e
155−applyE4 a b c d e = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b,ce c,ce d,ce e]
182+applyE4 a b c d e = wrap $ liftM (foldl1 App) $ sequence [unwrap a,unwrap b,unwrap c,unwrap d,unwrap e]
156− where ce = unsafeCoerceE
183+ where wrap = fmap Expression
184+ unwrap = fmap runExpression
157
185
158-- | Apply a function to 5 arguments
186-- | Apply a function to 5 arguments
159applyE5 :: ExpG (a -> b -> c -> d -> e -> f) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e -> ExpG f
187applyE5 :: ExpG (a -> b -> c -> d -> e -> f) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e -> ExpG f
160−applyE5 a b c d e f = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b,ce c,ce d,ce e,ce f]
188+applyE5 a b c d e f = wrap $ liftM (foldl1 App) $ sequence [unwrap a,unwrap b,unwrap c,unwrap d,unwrap e,unwrap f]
161− where ce = unsafeCoerceE
189+ where wrap = fmap Expression
190+ unwrap = fmap runExpression
162
191
163-- | Apply a function to 6 arguments
192-- | Apply a function to 6 arguments
164applyE6 :: ExpG (a -> b -> c -> d -> e -> f -> g) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e -> ExpG f -> ExpG g
193applyE6 :: ExpG (a -> b -> c -> d -> e -> f -> g) -> ExpG a -> ExpG b -> ExpG c -> ExpG d -> ExpG e -> ExpG f -> ExpG g
165−applyE6 a b c d e f g = unsafeCoerceE $ liftM (foldl1 App) $ sequence [ce a,ce b,ce c,ce d,ce e,ce f,ce g]
194+applyE6 a b c d e f g = wrap $ liftM (foldl1 App) $ sequence [unwrap a,unwrap b,unwrap c,unwrap d,unwrap e,unwrap f,unwrap g]
166− where ce = unsafeCoerceE
195+ where wrap = fmap Expression
196+ unwrap = fmap runExpression
167
197
168--------------------------------------------------------------------------------
198--------------------------------------------------------------------------------
169-- Generate modules
199-- Generate modules
@@ -180,23 +210,35 @@ data FunRef t = FunRef Name
180
210
181instance GenExp (FunRef t) where
211instance GenExp (FunRef t) where
182 type GenExpType (FunRef t) = t
212 type GenExpType (FunRef t) = t
183− expr (FunRef n) = return $ Var $ UnQual n
213+ expr (FunRef n) = return $ Expression $ Var $ UnQual n
184
214
185-- | Generate a ExportSpec for a given function item.
215-- | Generate a ExportSpec for a given function item.
186exportFun :: FunRef t -> ExportSpec
216exportFun :: FunRef t -> ExportSpec
217+#if MIN_VERSION_haskell_src_exts(1,16,0) && !MIN_VERSION_haskell_src_exts(1,17,0)
218+exportFun (FunRef name) = EVar NoNamespace (UnQual name)
219+#else
187exportFun (FunRef name) = EVar (UnQual name)
220exportFun (FunRef name) = EVar (UnQual name)
221+#endif
188
222
189-- | Add a declaration to the module. Return a reference to it that can be used to either apply the function to some values or export it.
223-- | Add a declaration to the module. Return a reference to it that can be used to either apply the function to some values or export it.
190addDecl :: Name -> ExpG t -> ModuleM (FunRef t)
224addDecl :: Name -> ExpG t -> ModuleM (FunRef t)
191addDecl name e = ModuleM $ do
225addDecl name e = ModuleM $ do
192− let (body, mods) = runExpM e
226+ let (body, mods) = runGenerate e
227+#if MIN_VERSION_haskell_src_exts(1,17,0)
228+ tell (mods, [FunBind [Match noLoc name [] Nothing (UnGuardedRhs $ runExpression body) Nothing]])
229+#else
193− tell (mods, [FunBind [Match noLoc name [] Nothing (UnGuardedRhs body) $ BDecls []]])
230+ tell (mods, [FunBind [Match noLoc name [] Nothing (UnGuardedRhs $ runExpression body) $ BDecls []]])
231+#endif
194 return $ FunRef name
232 return $ FunRef name
195
233
196-- | Extract the Module from a module generator.
234-- | Extract the Module from a module generator.
197runModuleM :: ModuleG -> String -> Module
235runModuleM :: ModuleG -> String -> Module
198runModuleM (ModuleM act) name =
236runModuleM (ModuleM act) name =
237+#if MIN_VERSION_haskell_src_exts(1,16,0)
238+ Module noLoc (ModuleName name) [] Nothing export (map (\md -> ImportDecl noLoc md True False False Nothing Nothing Nothing) $ S.toList imps) decls
239+#else
199 Module noLoc (ModuleName name) [] Nothing export (map (\md -> ImportDecl noLoc md True False Nothing Nothing Nothing) $ S.toList imps) decls
240 Module noLoc (ModuleName name) [] Nothing export (map (\md -> ImportDecl noLoc md True False Nothing Nothing Nothing) $ S.toList imps) decls
241+#endif
200 where (export, (imps, decls)) = runWriter act
242 where (export, (imps, decls)) = runWriter act
201
243
202-- | Generate the source code for a module.
244-- | Generate the source code for a module.
src/Language/Haskell/Generate/PreludeDef.hs+9−8
@@ -6,7 +6,7 @@
6module Language.Haskell.Generate.PreludeDef where
6module Language.Haskell.Generate.PreludeDef where
7
7
8import Language.Haskell.Exts.Syntax
8import Language.Haskell.Exts.Syntax
9−import Language.Haskell.Generate.Base
9+import Language.Haskell.Generate.Monad
10import Language.Haskell.Generate.TH
10import Language.Haskell.Generate.TH
11
11
12--------------------------------------------------------------------------------
12--------------------------------------------------------------------------------
@@ -60,28 +60,29 @@ fmap concat $ mapM declareNamedSymbol
60 , ('(++), "append'")
60 , ('(++), "append'")
61 , ('(!!), "index'")
61 , ('(!!), "index'")
62 , ('(==), "equal'")
62 , ('(==), "equal'")
63+ , ('(/=), "notequal'")
63 ]
64 ]
64
65
65(<>.) :: ExpG (b -> c) -> ExpG (a -> b) -> ExpG (a -> c)
66(<>.) :: ExpG (b -> c) -> ExpG (a -> b) -> ExpG (a -> c)
66(<>.) a b = dot' <>$ a <>$ b
67(<>.) a b = dot' <>$ a <>$ b
67
68
68tuple0 :: ExpG ()
69tuple0 :: ExpG ()
69−tuple0 = return $ Var $ Special UnitCon
70+tuple0 = returnE $ Var $ Special UnitCon
70
71
71tuple2 :: ExpG (a -> b -> (a,b))
72tuple2 :: ExpG (a -> b -> (a,b))
72−tuple2 = return $ Var $ Special $ TupleCon Boxed 2
73+tuple2 = returnE $ Var $ Special $ TupleCon Boxed 2
73
74
74tuple3 :: ExpG (a -> b -> c -> (a,b,c))
75tuple3 :: ExpG (a -> b -> c -> (a,b,c))
75−tuple3 = return $ Var $ Special $ TupleCon Boxed 3
76+tuple3 = returnE $ Var $ Special $ TupleCon Boxed 3
76
77
77tuple4 :: ExpG (a -> b -> c -> d -> (a,b,c,d))
78tuple4 :: ExpG (a -> b -> c -> d -> (a,b,c,d))
78−tuple4 = return $ Var $ Special $ TupleCon Boxed 4
79+tuple4 = returnE $ Var $ Special $ TupleCon Boxed 4
79
80
80tuple5 :: ExpG (a -> b -> c -> d -> (a,b,c,d,e))
81tuple5 :: ExpG (a -> b -> c -> d -> (a,b,c,d,e))
81−tuple5 = return $ Var $ Special $ TupleCon Boxed 5
82+tuple5 = returnE $ Var $ Special $ TupleCon Boxed 5
82
83
83cons :: ExpG (a -> [a] -> [a])
84cons :: ExpG (a -> [a] -> [a])
84−cons = return $ Var $ Special Cons
85+cons = returnE $ Var $ Special Cons
85
86
86instance Num t => Num (ExpG t) where
87instance Num t => Num (ExpG t) where
87 a + b = add' <>$ a <>$ b
88 a + b = add' <>$ a <>$ b
@@ -89,6 +90,6 @@ instance Num t => Num (ExpG t) where
89 a * b = mult' <>$ a <>$ b
90 a * b = mult' <>$ a <>$ b
90 negate a = negate' <>$ a
91 negate a = negate' <>$ a
91 abs a = abs' <>$ a
92 abs a = abs' <>$ a
92− fromInteger a = return $ Lit $ Int a
93+ fromInteger a = returnE $ Lit $ Int a
93 signum a = signum' <>$ a
94 signum a = signum' <>$ a
94
95
src/Language/Haskell/Generate/TH.hs+6−2
@@ -10,7 +10,7 @@ module Language.Haskell.Generate.TH
10
10
11import Data.Char
11import Data.Char
12import Language.Haskell.Exts.Syntax hiding (Name)
12import Language.Haskell.Exts.Syntax hiding (Name)
13−import Language.Haskell.Generate.Base hiding (Name)
13+import Language.Haskell.Generate.Monad hiding (Name)
14import Language.Haskell.TH
14import Language.Haskell.TH
15import Language.Haskell.TH.Syntax
15import Language.Haskell.TH.Syntax
16
16
@@ -36,9 +36,13 @@ declareNamedThing (thing, name, thingClass) = do
36 [| useValue $(lift md) $ $(conE thingClass) $(lift $ nameBase thing) |]
36 [| useValue $(lift md) $ $(conE thingClass) $(lift $ nameBase thing) |]
37 ]
37 ]
38
38
39− where overQuantifiedType f (ForallT bnds ctx t) = ForallT bnds ctx $ overQuantifiedType f t
39+ where overQuantifiedType f (ForallT bnds ctx t) = ForallT (map removeKind bnds) ctx $ overQuantifiedType f t
40 overQuantifiedType f x = f x
40 overQuantifiedType f x = f x
41
41
42+ removeKind :: TyVarBndr -> TyVarBndr
43+ removeKind (KindedTV n _) = PlainTV n
44+ removeKind x = x
45+
42-- | Declare a symbol, using the given name for the definition.
46-- | Declare a symbol, using the given name for the definition.
43declareNamedSymbol :: (Name, String) -> DecsQ
47declareNamedSymbol :: (Name, String) -> DecsQ
44declareNamedSymbol (func, name) = declareNamedThing (func, name, 'Symbol)
48declareNamedSymbol (func, name) = declareNamedThing (func, name, 'Symbol)
tests/doctests.hsc+1−2
@@ -20,18 +20,17 @@ import Data.List
20import System.Directory
20import System.Directory
21import System.FilePath
21import System.FilePath
22import Test.DocTest
22import Test.DocTest
23+import Prelude
23
24
24##ifdef mingw32_HOST_ARCH
25##ifdef mingw32_HOST_ARCH
25##ifdef i386_HOST_ARCH
26##ifdef i386_HOST_ARCH
26##define USE_CP
27##define USE_CP
27−import Control.Applicative
28import Control.Exception
28import Control.Exception
29import Foreign.C.Types
29import Foreign.C.Types
30foreign import stdcall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool
30foreign import stdcall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool
31foreign import stdcall "windows.h GetConsoleCP" c_GetConsoleCP :: IO CUInt
31foreign import stdcall "windows.h GetConsoleCP" c_GetConsoleCP :: IO CUInt
32##elif defined(x86_64_HOST_ARCH)
32##elif defined(x86_64_HOST_ARCH)
33##define USE_CP
33##define USE_CP
34−import Control.Applicative
35import Control.Exception
34import Control.Exception
36import Foreign.C.Types
35import Foreign.C.Types
37foreign import ccall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool
36foreign import ccall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool