Introduction

I would like to show you how I got APL working in emacs. You can interact with APL either through GNU-APL or through Dyalog-APL. I'll give you a quick rundown on both options.

Why use emacs?

I'm stubborn. I don't want to use RIDE for everything, even though it's capable. I like that I can bend emacs to do what I want. I also want to take notes on APL as I'm learning it through such wonderful resources as xpqz's introduction to APL. This setup lets you enter and evaluate APL using org-babel blocks inside org-mode. This might seem like a small thing, but there is so much insight you can gain by experimenting and just messing around with things. This method of interaction with the language encourages exploration and makes it easy.

GNU APL (gnu-apl-mode.el)

When we talk about this, we mean the wonderful emacs package by lokedhs. You will need this emacs package along-side an executable of gnu-apl on your system for this to work. This GNU implementation differs in syntax/glyphs from the Dyalog flavour of APL.

Pros

  • Native to emacs

  • Comes with cool input methods for typing glyphs (including the APL-Z layout)

  • Can show the APL keymap in a mini-buffer by calling M-x gnu-apl-show-keyboard once you have a session fired up

  • You can create plots using the in-built GNUPlot functions

  • The REPL is great

  • Everything is inspectable and customisable

Cons

  • The GNU implementation is not as widely used

  • Syntax/glyphs differ from what you may be used to with Dyalog APL

  • Documentation is sparse. You will find yourself reading the elisp to see how to do things (like plotting!)

Setup and use

The setup here is pretty simple. You can just load the package however you normally like. I'm using doom emacs, so in my packages.el I have:

(package! gnu-apl-mode)

I then issue SPC h r r to call doom/reload, which will fetch and install the package. I'm on macOS, so I also went ahead and installed gnu-apl using brew:

brew install gnu-apl

This will install the executable on your system, which gnu-apl-mode will then access and interact with.

To use this package, call gnu-apl in emacs, which will create a repl buffer and initiate an APL session for you to mess around with.

Input is taken care of by gnu-apl-mode which starts when the gnu-apl buffer pops up. Check out the keyboard by calling gnu-apl-show-keyboard. All keys are either prefixed by the super-key, or super-shift for the secondary layer. The APL-Z input method is also included in the package. Call set-input-method and select APL-Z. This gives you the option to input glyphs using '.' as a leader key. For example, we want the glyph 'iota', we hit .i and it prints in our repl.

I use this input method when I am working with org-babel blocks using the jupyter-apl kernel, which I will show you how to install in the next section.

Dyalog APL

I'm talking about the jupyter kernel for Dyalog APL, which is officially distributed by Dyalog.

Pros

  • The most widely used implementation of APL right now (2022)

  • Always being updated

  • Large community support

  • Great resources such as the APLWiki, APLcart and tatin.

  • Compatible with org-babel

Cons

  • Sometimes janky interaction with the jupyter-repl

  • Some massaging of the kernel necessary to work well in emacs

  • worse repl than with GNU APL (repl support through emacs-jupyter.el)

Setup and use

Setup is more involved than the native method. I will not cover setting up emacs-jupyter, or installing jupyter on your system (using PIP or otherwise). Those are the prerequisites. These are easily satisfied by using doom emacs, which does a lot of configuration work for you. Here are the steps:

Clone the repository for dyalog-jupyter and cd into it. Go ahead and open kernel.py (which lives in the 'dyalog_kernel' folder) in your favourite text editor (emacs). Search for the method out_result and look for a dictionary named _content. For me, it was on line 119. Inside of the _content dictionary there are two definitions of the data MIME-types. We want text/plain for babel blocks. This is what they want to receieve from the kernel. Comment out the key/value pair which contains 'html'. It should look like this after you edit it:

    def out_result(self, s):
        # injecting css: white-space:pre. Means no wrapping, RIDE SetPW will take care about line wrapping

        html_start = '<span style="white-space:pre; font-family: monospace">'
        html_end = '</span>'

        _content = {
            # 'output_type': 'display_data',
            'data': {'text/plain': s},
            #'data': {'text/html': html_start + html.escape(s, False) + html_end},
            'execution_count': self.execution_count,
            'metadata': {},

            # 'transient': ''
        }

After you've modified, go ahead and save this file. Go back to the project root and run the install script:

./install.sh

This should install the kernel to your jupyter kernelspec list. Check if it worked by running:

jupyter lab

It should take you to the jupyter interface and in the list of available kernels you should see 'Dyalog APL'.

To run this in org-babel, create a source block how you normally would and use jupyter-apl as the kernelspec:

#+begin_src jupyter-apl :session *new*
⍳5

#+end_src

Hitting enter inside this block should give you a list as output. If you get an error saying something about jupyter, try to run this in your terminal:

pip3 install jupyter

and then re-run the install.sh script in the dyalog-jupyter-kernel folder you pulled from git.

As for entering glyphs, follow the input guide in the section on gnu-apl and use the input method from that package.

Closing thoughts and wishlist

In all, what we have now is an excellent system for learning APL. With the org-babel integration, we can use it in a multi-lingual and literate fashion. For example, you want to write a report and need to do some quick calculations on a couple of vectors. You can pop in a few APL src blocks, show your workings and have the results neatly printed in your report. Want to graph or do some other manipulation that is cumbersome in APL? org-babel has facilities which let you pass outputs from one language block to another. I haven't looked at this in depth yet, so can't give a demonstration in this post.

Wishlist

  • A proper 'face' for jupyter-apl src blocks. Right now I'm turning off mixed-pitch-mode, since my setup is giving the APL source code a 'proportionately spaced' typeface rather than the desired monospaced one.

  • Syntax highlighting inside src blocks

Considerations

  • Check whether the font you use in emacs supports all the weird APL glyphs. Go to the APL wiki page on fonts and pick a nice one. I prefer PragmataPro Mono for monospaced text, and Source Sans Pro for proportionately spaced text.