DEV Community

Vehbi Sinan Tunalioglu
Vehbi Sinan Tunalioglu

Posted on • Originally published at thenegation.com

3

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

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay