
Hello,
You might already know this, but in case you don't: there is another
literate style:
... non-code ...
\begin{code}
... code ...
\end{code}
... non-code ...
in which you do not put prefixes to each line. (In fact the standard says
somewhere it is not recommended to mix the two styles if I remember right.)
I hope I am not being redundant!
Abhay
On Sat, Jun 21, 2008 at 11:48 PM, Martin Blais
Hello Haskell community!
I just did a marginally cool thing and I wanted to share it with you.
"rst-literals" is a small program I wrote a while ago in order to write documents in reStructuredText format that would embed SQL code for data models in them, a form of literal programming for SQL if you will; I would describe my needs for the schema in prose, and reST literal-blocks were used to embed SQL code, blocks that look like this::
CLASS Employee ( firstname VARCHAR, lastname VARCHAR )
I wrote the script to be entirely generic: it parses the reST documents using the docutils code and outputs only the literal-blocks, with indentation removed; you can then run your favourite interpreter/compiler on the result (in that case, psql to initialize a database).
Recently, while experimenting with Haskell, I started using both the literal (.lhs) and non-literal (.hs) styles of Haskell input, and I found the literal style a bit unpleasant to use, in particular, I don't like to have to prefix every line of code I write, despite the help that Emacs' haskell-mode provides.
So I tried pulling a similar trick and embedding Haskell code in literal-blocks within reST documents, extracting that code using rst-literals, and it turns out that it works like a charm. Here is an example makefile for doing this::
.SUFFIXES: .rst .hs
all: chap6
.rst.hs: rst-literals $< > $@
chap6: chap6.hs ghc --make chap6.hs
An example reST document with some embedded Haskell code follows this email. Note that since rst-literals is using the docutils parser, you can make use of all of the recursive reST syntax, sections, bulleted items and much more. Only the literal-blocks are extracted, anywhere they appear. You can also easily process the reST source into HTML pages or LaTeX documents using the tools that come with docutils.
You can find rst-literals here: http://furius.ca/pubcode/
Enjoy,
-- Martin
P.S. If there is a way to output cpp-like directives for GHC, like "#line <filename> <lineno>", it would be easy to modify rst-literals to generate those, so that compilation errors could refer to the source reST document instead of the extracted source.
chap6.hs: ----------------------------------------------------------------------
=========================================== Exercises from Hutton book, Chapter 6 ===========================================
.. contents:: .. 1 Introduction 2 Exercise 1 3 Exercise 2 4 Exercise 3 5 Exercise 4 6 Exercise 5 7 Exercise 6
Introduction ============
Bla bla bla blablablablablabla bla bla blabla. Bla bla bla blablablablablabla bla bla blabla. Bla bla bla blablablablablabla bla bla blabla. Bla bla bla blablablablablabla bla bla blabla. Bla bla bla blablablablablabla bla bla blabla. Bla bla bla blablablablablabla bla bla blabla.
Exercise 1 ========== ::
myexp :: Int -> Int -> Int myexp b 0 = 1 myexp b (n+1) = b * (myexp b n)
Exercise 2 ==========
(Exercise 2 consisted in derivations, so we mark the literal blocks as another type of block with "#!example", so that they don't get included in the output when only the "default" literal blocks get extracted. See rst-literals docstring for details.)
Length::
#!example 1 + (length [2, 3]) 1 + 1 + (length [3]) 1 + 1 + (1) 3
Drop::
#!example drop 3 [1, 2, 3, 4, 5] [] ++ drop 3 [2, 3, 4, 5] [] ++ [] ++ drop 3 [3, 4, 5] [] ++ [] ++ [] ++ [4, 5] [4, 5]
Init::
#!example init [1, 2, 3] [1] ++ init [2, 3] [1] ++ [2] ++ init [3] [1] ++ [2] ++ [] [1, 2]
Exercise 3 ==========
These are alternate versions of the example functions defined in the text::
and' :: [Bool] -> Bool and' [x] = x and' (x:xs) = x && and' xs
concat' :: [[a]] -> [a] concat' [] = [] concat' (x:xs) = x ++ concat' xs
replicate' :: Int -> a -> [a] replicate' 0 x = [] replicate' (n+1) x = (x : replicate' n x)
select' :: [a] -> Int -> a select' (x:xs) 0 = x select' (x:xs) (n+1) = select' xs n
elem' :: Eq a => a -> [a] -> Bool elem' _ [] = False elem' y (x:xs) | x == y = True | otherwise = elem' y xs
Exercise 4 ==========
The exercise asked to implement a function to merge two lists::
merge :: Ord a => [a] -> [a] -> [a] merge xs [] = xs merge [] xs = xs merge (x:xs) (y:ys) | x < y = (x : merge xs (y:ys)) | otherwise = (y : merge (x:xs) ys)
Exercise 5 ========== ::
msort :: Ord a => [a] -> [a] msort [] = [] msort [x] = [x] -- This is necessary to end the recursion. msort xs = merge (msort (fst hh)) (msort (snd hh)) where hh = halve xs
halve :: [a] -> ([a], [a]) halve xs = (take n xs, drop n xs) where n = (length xs) `div` 2
Some main program::
main = (putStrLn . show) (halve [1..17])
Exercise 6 ==========
(Too basic, I didn't bother.)
---------------------------------------------------------------------- _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe