Creating Haskell notebooks with org-mode
Tags: emacs, haskell, org, notebook
Published: 2021-09-05 03:30:51

### If you only knew the power of the Dark Side!

Tools like [Jupyter Notebook](https://ipython.org/notebook.html) are very well known and useful, although limited to a few languages. Wouldn't it be amazing to have this power to create notebooks with any other language?

<img src="https://media.giphy.com/media/7guVjhMF9qBKE/giphy.gif?cid=ecf05e47q37qmzwrptf00no6pjyccaigplovdcpjplwdj59x&rid=giphy.gif&ct=g">

In this text, we will focus on doing it with Haskell, although it is virtually possible to be done using any language.

Emacs has a very powerful mode called [org-mode](https://orgmode.org/), I once wrote [a text](https://dev.to/viglioni/installing-latex-themes-on-your-machine-emacs-org-mode-1k9e) about using it to write presentations with [beamer](https://ctan.org/pkg/beamer?lang=en). This same mode allows us to write code snippets (**and execute them!**), which is helpful to write notes/documents/presentations and export them to several formats like pdf, HTML, markdown, LaTeX and more!

{% youtube 1qOFYluebBg %}

### Pre-requisites

<img src="https://media.giphy.com/media/Y9zXpUBsE0INO/giphy.gif?cid=790b7611eda5c9355bae7673018d1b4da33d2ce80fac8628&rid=giphy.gif&ct=g">


Your Emacs will need some packages: `org`, `org-babel` and `haskell-mode`. If you use [spacemacs](http://spacemacs.org) it is enough to add these layers in your `.spacemacs`:

```emacs-lisp
    (
     ;; ...
     dotspacemacs-configuration-layers
      '( org
         haskell
         ;; ...
```

Of course, you must have [GHC](https://downloads.haskell.org/~ghc/) on your machine.


### Improving what we already have

It is important to note that once you have those packages installed, Emacs already knows how to execute Haskell blocks. The motivation of this text is to compile the learning I had these last few months of how to do it better.

<img src="https://media.giphy.com/media/NsIwMll0rhfgpdQlzn/giphy.gif?cid=790b7611531ae5c75a90d7cb9149659570d5bd1efff6f41b&rid=giphy.gif&ct=g">

To run a code block is as simple as:

```
    #+begin_src <language name>
      <code>
    #+end_src
```

and hit `C-c C-c`. If your Emacs knows how to compile it, it will execute the code and put the result below your code.




### Writing multiline Haskell code

The default way that `org-babel` compiles your code is using `GHCi`, so if you have to write a multiline code, then you need to do it as if we were inside a `GHCi` buffer:

```haskell
    :{
    -- a very verbose way to sum a sequence of numbers:  
    sumInts :: Int -> Int -> Int
    sumInts a b =
      if a == b
        then b
        else (+ a) $ (sumInts (a + 1) b)
    :}
    
    map (\[a,b] -> sumInts a b) [[0, 1] , [1, 3], [1,5], [2,10]]         
```

```haskell
    Prelude> [1,6,15,54]
```

*i.e.* we need to put the multiline part of the code inside `:{ :}` and what we want to be on the output on the last line. Also, it is important to note that, since it is running inside a `GHCi`, we will only see the result of the last call. 

We can use the `GHCi` commands like `:set -XDataKinds` too :))


You may be asking yourself what is that `:exports both`. As I said earlier, we can export this `org` file to several formats. The `:exports` tag defines if we want to export the code, result, both or none. You can check out the other tags [here](https://orgmode.org/manual/Using-Header-Arguments.html#Using-Header-Arguments).

**Fun fact**: GitHub understands `org` files without any manual export. You can use `org` files to READMEs, or even to post [your notebooks](https://github.com/Viglioni/lang-studies/blob/main/learn-you-a-haskell/chapter-11.org).

<img src="https://i.imgur.com/x2Vx409.gif">

### Formatting the output

As you may have noticed in the excerpt above, the output has a `Prelude>` "prefix", and it might get bigger if you import other libs or executes multiline blocks:

```haskell
    import Control.Monad
```

```haskell
    :{
    map
      (\x -> x*x + x + 1)
      [1..10]
    :}
```

```haskell
    Prelude Control.Monad| Prelude Control.Monad| Prelude Control.Monad| Prelude Control.Monad| [3,7,13,21,31,43,57,73,91,111]
```

<img src="https://c.tenor.com/crnWnvD4kWUAAAAC/annoyed-annoying.gif">

We can avoid that with the `:post` tag. This tag executes a function, of your choice, with the output of your code block as input. To get that, we will use... Yes, another code block :D

At the beginning of your code, add these lines:

```lisp
    #+name: org-babel-haskell-formatter
    #+begin_src emacs-lisp :var strr="" :exports code
      (format "%s"
              (replace-regexp-in-string
               (rx line-start
                   (+ (| alphanumeric blank "." "|" ">")))
               "" (format "%s" strr)))
    #+end_src      
```
<small> [This is the file I use to store this func in my repo](https://github.com/Viglioni/laurisp/blob/main/config/org-mode-extra-configs.org) </small>

For now on, on your Haskell code blocks, you add the `#+name:` you gave to that code block:

```
 #+begin_src haskell :exports both :post org-babel-haskell-formatter(*this*)
  <code>
 #+end_src
```

*e.g.*:

```haskell
    :{
    map
      (\x -> x*x + x + 1)
      [1..10]
    :}
```

```haskell
   [3,7,13,21,31,43,57,73,91,111]
```
#### You might be asking yourself right now:

##### Will you always have to write this template on the `#+begin_src`?

Unfortunately, yes. My recommendation is to create a snippet to generate this Haskell block code or to create some helper function that does that for you.

#####   Will you have to define the formatter function on every org file?

No! :D

You can add to your config files an org file with that function definition and import it on your Emacs initiation using the `org-babel-lob-ingest` function:

```emacs-lisp
    (with-eval-after-load "org"
      ;; load extra configs to org mode
      (org-babel-lob-ingest "~/path/to/org-config-file.org"))
```
  
Note that if you add a relative path (`./org-config-file.org`) it might fail.


### A wild awesome feature appears!

<img src="https://c.tenor.com/dwxrfKboa0YAAAAC/darth-vader.gif">

One of the coolest stuff about using `org` to write code snippets, even if you will not execute them, is that you can use specific modes while writing your snippet! 

With the cursor inside the `#+begin_src` block, call a function `org-edit-special` (`, '` on spacemacs default binding), then Emacs will open a new buffer with your language mode. To exit it, hit `C-c '`.


### Using external Haskell libs with Stack

<img src="https://c.tenor.com/vjlozeBNuwEAAAAC/ive-been-looking-forward-to-this-dooku.gif">

This one was the trickiest to me, mostly because I'm not very familiar with the [stack](https://docs.haskellstack.org/en/stable/) ecosystem. Maybe this is not the best way of doing it, but this is the way that I achieved it.

`Stack` has a global project by default, you can check it out on `~/.stack/global-project`. Inside this directory, create a new project:

```shell
   $ stack new org-haskell new-template
```

On `~/.stack/global-project/stack.yaml` add the following:

```yaml
            packages:
              - org-haskell
```

After that, all the libs you have imported on your `.stack/global-project/org-haskell/packages.yaml` will be available on `stack ghci`. For `org-babel` to use it instead of regular `GHCi`, set this variable on your configs:

```emacs-lisp
    (setq haskell-process-type 'stack-ghci)
```
  

### Know the power of the Dark Side!

<img src="https://media.giphy.com/media/xTiIzIhgJ6ZrY3cZeo/giphy.gif?cid=790b76119c80a5db5863d2363f1ec9e44c75267bf50b1f35&rid=giphy.gif&ct=g">

I do hope this is helpful for you.

`org-mode` is a **very** powerful tool, I do recommend that you know it and use it!

Stay safe, use masks (even if you already got your shots!) and use Emacs
xoxo



<small> [The header picture](https://www.reddit.com/r/emacs/comments/lf2cfm/just_in_case_yall_were_looking_for_some_new/) </small>