@@ -3,9 +3,11 @@
3{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE UndecidableInstances #-}
4{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
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
9 , useValue, useCon, useVar
11 , useValue, useCon, useVar
11 , applyE, applyE2, applyE3, applyE4, applyE5, applyE6
13 , applyE, applyE2, applyE3, applyE4, applyE5, applyE6
@@ -19,6 +21,7 @@ module Language.Haskell.Generate.Base
20 , runModuleM
22 , runModuleM
21 , generateModule
23 , generateModule
@@ -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
35--------------------------------------------------------------------------------
41--------------------------------------------------------------------------------
36-- Generate expressions
42-- Generate expressions
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)
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
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)
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
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
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
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
59− return $ Case v' alt'
74+ return $ Expression $ Case (runExpression v') alt'
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 "+"
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
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
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
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
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:
113+-- >>> putStrLn $ generateExp $ expr "I'm a string!"
114+-- ['I', '\'', 'm', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '!']
96class GenExp t where
116class GenExp t where
97 type GenExpType t :: *
117 type GenExpType t :: *
@@ -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
126+instance GenExp (Expression t) where
127+ type GenExpType (Expression t) = t
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
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
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
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)
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
129--------------------------------------------------------------------------------
153--------------------------------------------------------------------------------
130-- Apply functions
154-- Apply functions
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
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 <>$
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
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
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
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
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
168--------------------------------------------------------------------------------
198--------------------------------------------------------------------------------
169-- Generate modules
199-- Generate modules
@@ -180,23 +210,35 @@ data FunRef t = FunRef Name
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
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)
187exportFun (FunRef name) = EVar (UnQual name)
220exportFun (FunRef name) = EVar (UnQual name)
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]])
193− tell (mods, [FunBind [Match noLoc name [] Nothing (UnGuardedRhs body) $ BDecls []]])
230+ tell (mods, [FunBind [Match noLoc name [] Nothing (UnGuardedRhs $ runExpression body) $ BDecls []]])
194 return $ FunRef name
232 return $ FunRef name
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
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
200 where (export, (imps, decls)) = runWriter act
242 where (export, (imps, decls)) = runWriter act
202-- | Generate the source code for a module.
244-- | Generate the source code for a module.