French ↓ Menu ↓

# Haskell Tutorials, a tutorial

tl;dr: Some hints on how to make great documentation for Haskell libraries.

1. Create a `Tutorial` module containing nothing except documentation.
2. Mention the `Tutorial` module in your `cabal` description
3. Use `doctest` to check your documentation is up to date
4. For more complex real world examples, link to the source of some test.

Great documentation make a big difference. A bad documentation could simply make people not using your lib.

My friend was learning Haskell. To start he tried a Haskell library to make a small application. The documentation was deprecated to the point he wasn’t able to make a basic example work. How do you believe he felt? What does he thought about Haskell in general?

So here are my hint on how to make a great documentation in Haskell.

Documentation can take many different form.

1. Tutorials/Guides – write some prose which friendly take a user by hand and help him
2. Examples – how to use each function
3. Generated API Documentation – haddock

## Hints

### Tutorials/Guides

1. Create a new module named `Tutorial` (or `Guide.GuideTopic`)
2. Create a link to the tutorial in the cabal description
3. Create a link to the tutorial in your README
4. Here is an example some `Tutorial` module content:

    {-# OPTIONS_GHC -fno-warn-unused-imports #-}
    {-|
     Use @my-package@ if you want to ...
    -}
    module Data.Duration.Tutorial (

      -- * Introduction
      -- $introduction

      -- ** Subsection
      -- $subsection

      ) where

    import Data.Duration

    {- $introduction

    So here how you use it:

     >>> humanReadableDuration 1002012.002
     "11 days 14 hours 20 min 12s 2ms"

    The function is 'humanReadableDuration' and
    the you'll be able to click on it to go
    to its definition.

    You can add images: <<path-to-image.png title>>
    and links: <http://haskell-lang.org haskell>.

    -}

    {- $subsection

    This is a chuck of documentation
    not attached to any particular Haskell
    declaration with an untested code block:

    > answer = 42

    -}

To prevent obsolescence of your tutorial, use `doctest`.

That way when you’ll do a `stack test` or `cabal test` you’ll get errors if some example doesn’t work anymore.

### Examples (doctest)

`doctest` is a great way to provide examples in your code documentation. These example will then be used as tests. Apparently it comes from Python community.

To use `doctest`, this is very simple:

    -- | My function description
    --
    -- >>> myFunction 3 4
    -- 7
    myFunction :: Int -> Int -> Int
    myFunction = (+)

And to make it works simply verify you have a `test` bloc in your `.cabal` file looking like this:

    test-suite doctest
      type: exitcode-stdio-1.0
      hs-source-dirs: test
      main-is: DocTest.hs
      build-depend: base >= 4.7 && < 5
                  , <YOUR_LIBRARY>
                  , Glob >= 0.7
                  , doctest >= 0.9.12

and in `test/DocTest.hs` simply use

    module Main where

    import DocTest
    import System.FilePath.Glob (glob)

    main = glob "src/**/*.hs" >>= docTest

Now `stack test` or `cabal test` will check the validity of your documentation.

## Bonuses

### Verifying documentation coverage

1. Install haddock `stack install haddock` or `cabal install haddock`
2. Launch haddock without output format:

    > haddock src/**/*.hs
    Haddock coverage:
     100% ( 15 / 15) in 'Data.Duration'
     100% (  3 /  3) in 'Data.Duration.Tutorial'

### Continuous Integration

There are plenty of alternative solution. I provide the one I believe would be used by most people. So if you use `github` simply create an account on `travis`.

Add a `.travis.yml` file in your repo containing the content of the file here and remove the builds you don’t need. It will build your project using a lot of different GHC versions and environemnts.

If you are afraid by such its complexity you might just want to use this one:

    sudo: false

    addons:
      apt:
        packages:
          - libgmp-dev

    # Caching so the next build will be fast too.
    cache:
      directories:
      - $HOME/.stack

    before_install:
    # Download and unpack the stack executable
    - mkdir -p ~/.local/bin
    - export PATH=$HOME/.local/bin:$PATH
    - travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'

    script:
      - stack setup && stack --no-terminal --skip-ghc-check test

Don’t forget to activate your repo in travis.

For some bonus points add the build status badge in your `README.md` file:

    [![Build Status](https://travis-ci.org/user-name/project-name.svg?branch=master)](https://travis-ci.org/user-name/project-name)

Congratulation! Now if you break your documentation examples, you’ll get notified.

### Badges

You could add badges to your `README.md` file.

Here is a list of some: `shields.io`

#### Hackage

    [![Hackage](https://img.shields.io/hackage/v/packagename)](https://hackage.haskell.org/package/packagename)

#### Stackage

If you didn’t declared your package to `stackage`, please do it. It isn’t much work. Just edit a file to add your package. And you’ll could be able to add another badge:

    [![packagename on Stackage LTS](http://stackage.org/package/packagename/badge/lts-3)](http://stackage.org/lts/package/packagename)

See Stackage Badges for more informations.

### Creating a new project with `stack`

If you use `stack` I suggest you to use the `tasty-travis` template. It will include the boilerplate for:

- tests
- doctest
- benchmark
- travis CI
- a README file to help you start

So edit your `~/.stack/config.yaml` like this:

    templates:
      params:
          author-name: Your Name
          author-email: your@mail.com
          copyright: 'Copyright: (c) 2016 Your Name'
          github-username: yourusername
          category: Development

And then you can create a new projec with:

    stack new my-project tasty-travis

## Generated Documentation

Even not doing anything, if you submit your library to hackage, haddock should generate some API documentation for free.

But to make real documentation you need to add some manual annotations.

Functions:

    -- | My function description
    myFunction :: T1 -- ^ arg1 description
               -> T2 -- ^ arg2 description
    myFunction arg1 arg2 = ...

Data:

    data MyData a b
      = C1 a b -- ^ doc for constructor C1
      | C2 a b -- ^ doc for constructor C2

    data MyData a b
      = C { a :: TypeA -- ^ field a description
          , b :: TypeB -- ^ field b description
          }

Module:

    {-|
    Module    : MyModule
    Description: Short description
    Copyright : (c)
    License : MIT

    Here is a longer description of this module.
    With some code symbol @MyType@.
    And also a block of code:

    @
    data MyData = C Int Int

    myFunction :: MyData -> Int
    @

    -}

Documentation Structure:

    module MyModule (
      -- * Classes
      C(..),
      -- * Types
      -- ** A data type
      T,
      -- ** A record
      R,
      -- * Some functions
      f, g
      ) where

That will generate headings.

## Other Random Ideas

In Haskell we have great tools like `hayoo!` and `hoogle`.

And `hackage` and `stackage` provide also a lot of informations.

But generally we lack a lot of Tutorials and Guides. This post was an attempt to help people making more of them.

But there are other good ideas to help improve the situation.

### Create a doc with link to best practices

In clojure when you create a new project using `lein new my-project` a directory `doc` is created for you. It contains a file with a link to this blog post:

- What to write

### Having a page by function/symbol with comments

If you try to search for some clojure function on a search engine there is a big chance the first result will link to:

- `clojuredocs.org`: try to search for `reduce`, `update-in` or `index` for example

For each symbol necessiting a documentation. You don’t only have the details and standard documentation. You’ll also get:

- Responsive Design (sometime you want to look at documentation on a mobile)
- Contributed Examples
- Contributed See Also section
- Contributed notes/comments

`clojuredocs.org` is an independant website from the official Clojure website.

Most of the time, if you google the function you search you end up on clojuredocs for wich there are many contributions.

Currently stackage is closer to these feature than hackage. Because on stackage you have access to the README and also some comments by package.

I believe it would be more efficient to have at least a page by module and why not a page by symbol (data, functions, typeclasses…).

For example, we could provide details about `foldl` for example. Also as there would be less information to display, it will make the design cleaner.

Today, if you want to help documenting, you need to make a PR to the source of some library. While if we had an equivalent to clojuredocs for Haskell, adding documentation would simply be a few clicks away:

1. login
2. add/edit some example, comments, see-also section

There are more than 23k people on `/r/haskell`. If only 1% of them would take 10 minutes adding a bit of documentation it will certainly change a lot of things in the percieved documentation quality.

And last but not least,

## Design is important

Design is a vague word. A good design should care not only about how something look, but also how users will interact with it. For example by removing things to focus on the essential.

When I stumble upon some random blog post or random specification in the Haskell community, I had too much a feeling of old fashioned design.

If you look at node.js community lot of their web page look cleaner, easier to read and in the end, more user friendly.

Haskell is very different from node, I wouldn’t like to replace all long and precise documentation with short human unprecise concepts. I don’t want to transform scientific papers by tweets.

But like the scientific community has upgraded with the use of LaTeX, I believe we could find something similar that would make, very clean environment for most of us. A kind of look and feel that will be

- modern
- device friendly (either on computer, mobile, tablet)
- efficient, focus on what is most important and is helpful

RSS · Tweet · FB
These social sharing links preserve your privacy
↑ Top ↑
Published on 2016-05-06
Follow @yogsototh
Yann Esposito©
Done with Vim spacemacs & nanoc Hakyll

ADA: `DdzFFzCqrhtAvdkmATx5Fm8NPJViDy85ZBw13p4XcNzVzvQg8e3vWLXq23JQWFxPEXK6Kvhaxxe7oJt4VMYHxpA2vtCFiP8fziohN6Yp`