4[](http://travis-ci.org/bennofs/haskell-generate)
8If 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.
12First, you need to import this library:
15import Language.Haskell.Generate
18This module reexports `Language.Haskell.Exts.Syntax`, because haskell-generate builds on top of that.
20There 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`.
22How do you build expressions? There is a number of predefined expressions for the functions in the
23Prelude. 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":
26readNamesFile' :: ExpG (IO String)
27readNamesFile' = readFile' <>$ expr "names"
30Here 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`.
32Now 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
33a module with those names.
35Here's how we generate our module:
40 d <- addDecl (Ident "main") $ applyE2 bind' readNamesFile' putStrLn'
41 return $ Just [exportFun d]
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`.
46The only thing left to do is to generate the actual source code for the module, for which we
47use the `generateModule` function, which takes the module name as an argument:
51main = putStrLn $ generateModule myModule "Main"
54If you run the program, you'll get the following output:
57module Main (main) where
58import qualified GHC.Base
59import qualified System.IO
61 = (GHC.Base.>>=) (System.IO.readFile ['n', 'a', 'm', 'e', 's'])
65If you run this code, you'll get the contents of the "names" file. The code is a bit ugly and uses
66qualified imports to avoid name clashes, but it works.
70Until 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.
72You can do that using the `useValue` from haskell-generate. Let's look at the type of `useValue`:
75useValue :: String -> Name -> ExpG t
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.
80For example, suppose we want to use the function `permutations` from Data.List. We write the following definition for it:
83permutations' :: ExpG ([a] -> [[a]]) -- Here we given an explicit type for permutations'. This is not checked, so make sure it's actually right!
84permutations' = useValue "Data.List" (Ident "permutations") -- "permutations" is an identifier, not a symbol, so we use the "Ident" constructor.
87## Using TH to automagically import functions
89If 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.
91Using the example from the previous section, we could also import the `permutations` function like this:
94-- at the top of the file:
95{-# LANGUAGE TemplateHaskell #-} -- Enable template haskell
96import Data.List (permutations) -- The function needs to be available at compile time
98declareFunction 'permutations -- This generates the same code as above, but is more type-safe because you don't have to specify the type yourself.
104If 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.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list