Creating Haskell notebooks with org-mode

If you only knew the power of the Dark Side!

Tools like Jupyter Notebook 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?

In this t…


This content originally appeared on DEV Community and was authored by Laura Viglioni

If you only knew the power of the Dark Side!

Tools like Jupyter Notebook 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?

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, I once wrote a text about using it to write presentations with beamer. 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!

Pre-requisites

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

    (
     ;; ...
     dotspacemacs-configuration-layers
      '( org
         haskell
         ;; ...

Of course, you must have 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.

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:

    :{
    -- 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]]         
    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.

Fun fact: GitHub understands org files without any manual export. You can use org files to READMEs, or even to post your notebooks.

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:

    import Control.Monad
    :{
    map
      (\x -> x*x + x + 1)
      [1..10]
    :}
    Prelude Control.Monad| Prelude Control.Monad| Prelude Control.Monad| Prelude Control.Monad| [3,7,13,21,31,43,57,73,91,111]

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:

    #+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      

This is the file I use to store this func in my repo

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

    :{
    map
      (\x -> x*x + x + 1)
      [1..10]
    :}
   [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:

    (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!

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

This one was the trickiest to me, mostly because I'm not very familiar with the stack 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:

   $ stack new org-haskell new-template

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

            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:

    (setq haskell-process-type 'stack-ghci)

Know the power of the Dark Side!

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

The header picture


This content originally appeared on DEV Community and was authored by Laura Viglioni


Print Share Comment Cite Upload Translate Updates
APA

Laura Viglioni | Sciencx (2021-09-05T03:30:51+00:00) Creating Haskell notebooks with org-mode. Retrieved from https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/

MLA
" » Creating Haskell notebooks with org-mode." Laura Viglioni | Sciencx - Sunday September 5, 2021, https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/
HARVARD
Laura Viglioni | Sciencx Sunday September 5, 2021 » Creating Haskell notebooks with org-mode., viewed ,<https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/>
VANCOUVER
Laura Viglioni | Sciencx - » Creating Haskell notebooks with org-mode. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/
CHICAGO
" » Creating Haskell notebooks with org-mode." Laura Viglioni | Sciencx - Accessed . https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/
IEEE
" » Creating Haskell notebooks with org-mode." Laura Viglioni | Sciencx [Online]. Available: https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/. [Accessed: ]
rf:citation
» Creating Haskell notebooks with org-mode | Laura Viglioni | Sciencx | https://www.scien.cx/2021/09/05/creating-haskell-notebooks-with-org-mode/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.