Import:
= Mercurry =

Now is the time for all programming languages to insist on
Read-Eval-Print Loops (REPLs).

https://www.youtube.com/watch?v=8Ab3ArE8W3s[The edit-compile-run cycle is an
vestige of punched cards and human operators]. Computers have long been
powerful enough to provide an interactive environment. Indeed, decades ago, my
very first 8-bit home computer had a BASIC interpreter. I learned quickly from
https://tll.mit.edu/teaching-resources/assess-learning/how-to-give-feedback/[high-quality
immediate feedback].

Can we improve on old-school shells? Perhaps not always. I still fire up
https://en.wikipedia.org/wiki/Bash_(Unix_shell)[bash] for basic tasks.
Sometimes all I want is the simple and effective
https://en.wikipedia.org/wiki/Request%E2%80%93response[request-response] model.

However, the mass adoption of spreadsheets suggests that a richer interface may
often be better. Spreadsheets break free from the strict linear structure of a
command-line session. While spreadsheets are popularly associated with less
technical users, it seems programmers of all stripes could benefit from being
able to nimbly hop around while manipulating snippets of code and data.

Indeed, https://jupyter.org/[Jupyter Notebooks] show that sprucing up a humble
REPL can reap huge rewards. Their example inspires us to build a similar
web-based interactive development environment for our Haskell compiler, which
we call Mercurry.

Our Haskell compiler runs in the browser, so unlike Jupyter, Mercurry is small
and self-contained. There is no server doing the actual computation, which is
convenient, but also limits our power.

[ ]:
fibs = 0:1:zipWith(+) fibs (tail fibs)

fibs!!10
fibs!!(fibs!!10)
Unlike GHCi, rather than one definition or statement or expression at a time,
we accept an arbitrary mix of them. This is almost the same, but it does mean
that if there is a parse error anywhere then nothing happens.

== AsciiDoctor ==

For marking up text, we use AsciiDoc instead of Markdown.

We rely on `asciidoctor.min.js` from

 * https://github.com/asciidoctor/asciidoctor.js/releases

By trial and error, I figured out that after including this script, the
following should be called:

----------------------------------------------------------------
Asciidoctor$$module$build$asciidoctor_browser();
----------------------------------------------------------------

and then
https://mrduguo.github.io/asciidoctor.org/docs/install-and-use-asciidoctorjs/[the
official instructions] work as advertised. For example:

----------------------------------------------------------------
element.innerHTML = Opal.Asciidoctor.$convert(src, Opal.hash2(['attributes'], {'attributes': ['showtitle']}));
----------------------------------------------------------------

== MathJax ==

When running an AsciiDoc cell, after calling AsciiDoctor, we call MathJax to
render equations.

I prefer indicating equations with just backslashes and parentheses or square
brackets to AsciiDoctor's more verbose syntax, but sometimes this causes issues
with unwanted AsciiDoc substitutions. When needed, we work around this issue
with AsciiDoc's passthrough mechanism.

When our page loads, our `init()` function renders AsciiDoc snippets with the
JavaScript port of AsciiDoctor, and calls MathJax to render any equations. We
ensure MathJax has already been initialized by calling `init()` after MathJax
is ready.

----------------------------------------------------------------
window.MathJax = {
  startup: {
    ready: () => {
      MathJax.startup.defaultReady();
      init();
    }
  }
};
----------------------------------------------------------------

However, another race arises. These lines only work if evaluated before loading
MathJax. On other pages, we load MathJax in the head section, so the browser
can fetch it in parallel as early as possible. For pages like this one, we load
MathJax last.

== Nonstandard Output ==

Tired of boring text output? Then call `jsEval` to, say, modify the HTML DOM.
The JavaScript variable `repl.outdiv` refers to a DIV element suitable for
placing output, as it is refreshed every run.

[ ]:
jsEval [r|repl.outdiv.innerHTML = `<svg version="1.1" height="100" width="100" xmlns="http://www.w3.org/2000/svg"><circle r="45" cx="50" cy="50" fill="peachpuff" /></svg>`;|]

Ben Lynn blynn@cs.stanford.edu 💡