Literate Haskell with Markdown

vst

Vehbi Sinan Tunalioglu

Posted on January 9, 2024

Literate Haskell with Markdown

This is a short guide to writing Literate Haskell programs using Markdown.

The source code of this very Web page is a Markdown file with a frontmatter. At
the same time, the source code is a Literate Haskell program, i.e. you can
compile and run it.

Let's write a small program.

First, we define a Haskell module:

module Main where
Enter fullscreen mode Exit fullscreen mode

... and then, define a main function:

main :: IO ()
main = putStrLn "Hello World!"
Enter fullscreen mode Exit fullscreen mode

By now, we have implemented a valid Haskell program that is embedded in our
Markdown document (the source code). We will define two more functions to
demonstrate doctest.

-- | Adds 7 to the given 'Int'.
--
-- >>> add7 35
-- 42
add7 :: Int -> Int
add7 = (+) 7

-- | Divides 42 by the given 'Int'.
--
-- >>> div42 1
-- 42
-- >>> div42 2
-- 21
-- >>> div42 3
-- 14
-- >>> div42 6
-- 7
-- >>> div42 7
-- 6
-- >>> div42 0
-- 0
-- >>> div42 42
-- 1
div42 :: Int -> Int
div42 = div 42
Enter fullscreen mode Exit fullscreen mode

We need to install markdown-unlit, a custom unlit program to extract Haskell
code from Markdown files. Once installed, we can compile our program:

$ ghc -pgmLmarkdown-unlit Main.lhs
[1 of 1] Compiling Main             ( Main.lhs, Main.o )
Linking Main ...
Enter fullscreen mode Exit fullscreen mode

This will produce your executable (Main) along with Main.o and Main.hi
files. You can run your program:

$ ./Main
Hello World!
Enter fullscreen mode Exit fullscreen mode

We could have run the program directly using runhaskell, too:

$ runhaskell -pgmLmarkdown-unlit Main.lhs
Hello World!
Enter fullscreen mode Exit fullscreen mode

Also, we can produce the Haskell code of interest:

$ markdown-unlit -h label Main.lhs Main.hs
Enter fullscreen mode Exit fullscreen mode

We can study Main.hs or run doctest on it (do not forget to re-generate
Main.hs after changing the source code):

$ doctest Main.hs
label:51: failure in expression `div42 0'
expected: 0
 but got: *** Exception: divide by zero
          ^

Examples: 8  Tried: 7  Errors: 0  Failures: 1
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
vst
Vehbi Sinan Tunalioglu

Posted on January 9, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Executable Blog Posts: Second Take
haskell Executable Blog Posts: Second Take

August 11, 2024

Literate Haskell with Markdown
haskell Literate Haskell with Markdown

January 9, 2024