Reputation: 1229
Is there an easy way to convert a literate Haskell file (.lhs
) to a regular Haskell (.hs
) source file?
I thought there might be a GHC option, but the GHC manual doesn't seem to have much information on literate programs or the .lhs
format. The word "literate" doesn't even appear in the index!
The Literate programming link on the Wiki includes links to scripts that convert between "bird" and "\begin{code}
..\end{code}
" styles or convert .lhs
to TeX format, but that's it.
Upvotes: 8
Views: 3241
Reputation: 320
Just hack together a quick script like the one below :) This converts the literate parts to line-comments.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
import Control.Monad (forM_)
import System.FilePath.Glob (glob)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import System.FilePath (replaceExtension)
import Development.Shake.Command
unLiterateHaskell :: T.Text -> T.Text
unLiterateHaskell = T.unlines . map processLine . T.lines
processLine :: T.Text -> T.Text
processLine (T.stripEnd -> txt) = case T.uncons txt of
Nothing -> txt
Just ('>', txt) -> T.drop 1 txt -- may need to adjust here depending on style
Just{} -> "-- " <> txt
main :: IO ()
main = do
files <- glob "**/*.lhs"
forM_ files $ \f -> do
src <- T.readFile f
T.writeFile (replaceExtension f "hs") (unLiterateHaskell src)
Exit _ <- cmd ("mv" :: String) f (f <> ".bak")
pure ()
Upvotes: 0
Reputation: 50884
GHC itself uses a standalone C program called unlit
to process .lhs
files. You can probably find it installed somewhere in your GHC installation. If you run it, it shows a few command line options without explanation:
$ cd ~/.stack/programs/x86_64-linux/ghc-8.6.4/lib/ghc-8.6.4/bin
$ ./unlit
usage: unlit [-q] [-n] [-c] [-#] [-P] [-h label] file1 file2
Digging into the source code, it looks like the options are:
-q "quiet": ignore certain errors, so permit missing empty lines before and after
"bird" style and accept completely empty programs
-n (default) "noisy": opposite of -q, so be noisy about errors
-c "crunch": don't leave blank lines where literate comments are removed
-# delete lines that start with "#!"
-P suppress CPP line number pragma, but only matters if `-h` is supplied
-h File name for an initial `#line` pragma
So, the command line:
$ /path/to/unlit -c myfile.lhs myfile.hs
will probably do a good job converting myfile.lhs
:
This is a literate program
> main :: IO ()
using both code styles
\begin{code}
main = putStrLn "hello"
\end{code}
to an "illiterate" program myfile.hs
:
main :: IO ()
main = putStrLn "hello"
For "bird" style, it actually replaces the '>' character with a space and leaves the rest of the indentation in place, so for my example above, both lines in myfile.hs
are indented with two spaces, which could be a drawback.
Upvotes: 10