Thoughts on the Elm repl

I use the Elm repl quite a bit, and think it would be much more useful
if one could more easily enter multi-line code. One possiblity
would be to have a mode in which input is terminated by by typing
a period, so that, for example, one could say

> hello : String -> String 
hello name = "Hello " ++ name  ++ "!" .
> hello "John" .
"Hello John!"
>

I propose that this be a mode, since for many (most) folks,
the current behavior is just fine. For example:

$ elm repl --geek
Please terminate input by typing a period
> 

The reason I advocate a period for terminating input is that
it is a single key stroke and has low visual noise. Erlang
uses this. OCAML uses ;;

PS. Besides my personal interest in this, such an option would make
the repl more useful for teaching Elm apart from its use in web browsers.

4 Likes

That’s interesting. Can you link to examples of other REPLs that do this? I’d want to play around with them a little bit!

I recall that python gives you new lines based on the structure of the input. So if you make a def, pressing enter once gives you the next line, and pressing it again evaluates the definition. I think! That kind of system is pretty neat, and then it doesn’t need any special mode or syntax.

Anyway, please share links to REPLs you have seen that do this in different ways. (Ideally they have an online one, but otherwise some online docs about their REPL works.)

3 Likes

Here is one: https://try.ocamlpro.com/

It works a bit differently than the ocaml repl in my terminal
window. If you type something, then press RETURN, the repl
helpfully adds ;; and evaluates the expression. But if you
type shift-RETURN, it acts as the terminal repl does. Thus, one
can do the below:

# 1 +
# 2 +
# 3 ;;
- : int = 6
#

I’ll try to find more, preferably online. In the meantime,
below is another example is Coq. Like Erlang, it uses
a period as terminator.

$ coqtop
Welcome to Coq 8.8.1 (July 2018)

Coq < Require Import Arith.
[Loading ML file z_syntax_plugin.cmxs ... done] ...

Coq < Require
Coq < Import
Coq < ZArith.
[Loading ML file omega_plugin.cmxs ... done]

$ coqtop
Welcome to Coq 8.8.1 (July 2018)

Coq < Require Import Arith.
[Loading ML file z_syntax_plugin.cmxs ... done]
[Loading ML file quote_plugin.cmxs ... done]
[Loading ML file newring_plugin.cmxs ... done]

Coq < Definition sqr :=
Coq < fun x:nat => x*x.
sqr is defined

Coq < Eval compute in (sqr 2).
     = 4
     : nat

Coq < Eval
Coq < compute
Coq < in (sqr (sqr 2)).
     = 16
     : nat

SQL repls work in similar ways. Both mysql and psql let you enter SQL linewise, and only evaluate when you enter a semicolon:

$ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 756
Server version: 5.6.41 Homebrew

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT *
    ->   FROM users;

Aha! Here is an online Erlang repl: http://www.tryerlang.org/

Example:

Erlang R15B (erts-5.9)
> 1 + 1.
2
> 1
> + 
> 2.
3
> 3
> div
>  2.
1
> Name =
> alice .
alice
> Name .
alice
>  

The Prolog repls have a way of doing this, which is to issue a special ‘sandbox’ command [user].

?- [user]
likes(mary,cake).
likes(john,cake).

Ctrl-D

?- likes(X, cake).

The F# repl also uses ;; as OCaml

Ammonite.REPL is an alternative for scala.

Multi-line editing in Ammonite.REPL

Quoting documentation from the Li Haoyi (its author):

You can use the Up and Down arrows to navigate between lines within your snippet. Enter only executes the code when you’re on the last line of a multi-line snippet, meaning you can take your time, space out your code nicely, and fix any mistakes anywhere in your snippet. History is multi-line too, meaning re-running a multi-line snippet is trivial, even with tweaks.

Long gone are the days where you’re desperately trying to cram everything in a single line, or curse quietly when you notice a mistake in an earlier line you are no longer able to fix. No more painstakingly crafting a multi-line snippet, and then having to painstakingly fish it line by individual line out of the history so you can run it again!

End Quote

The actual web page also has neat little gif animations of the REPL including an illustration of the multiline editing (just below the block I quoted above).

I don’t know if this helps the OP, but an alternative/addition to the elm REPL is litvis, which allows you to create literate elm in the Atom or VSCode editors without the overhead of setting up TEA or creating modules. It can act as a multi-line REPL with the additional benefit of being embedded in markdown for contextual narrative.

For example,

Consider the coding of the following party trick:

Think of a number. Double it. Multiply that number by five. 
Now divide it by the number you first thought of. 
And finally, subtract seven from the number and write it down.

The number written on the paper is ... 3. Ta dah!

```elm {literate}
always3 : Int -> Int
always3 n =
    double n |> multiply 5 |> divide n |> add -7
```

```elm {literate raw}
partyTrick : Int
partyTrick =
    always3 146470
```
3
1 Like

litvis looks really impressive. I will give it a try.

I realised the example above is rather poor. Here’s the output of a more explanatory example of reactive Elm in litvis.

approximate_e

Alex Kachkaev gave a talk at Elm-Europe this year literate elm (in the context of building a system for literate visualization):

Summary:
https://www.youtube.com/watch?v=D_KwyxSjRjw

Full talk:
https://www.youtube.com/watch?v=K-yoLxnm95A&list=PL-cYi7I913S-VgTSUKWhrUkReM_vMNQxG&index=7&t=0s

3 Likes

Kotlin’s REPL seems to do this nicely, that is parse multiple lines until a full statement has been detected. Haven’t worked with it a ton, though.
In IDEA, you commit REPL statements with Ctrl+Enter.

Furthermore, the fish shell does something similar. It even auto-indents!

@jwoLondon litVis looks really good. I just tried to install it, but at npm install --global elm prettier prettier-plugin-elm I got the error

npm ERR! path /usr/local/bin/elm
npm ERR! code EEXIST
npm ERR! Refusing to delete /usr/local/bin/elm: is outside /usr/local/lib/node_modules/elm and not a link
npm ERR! File exists: /usr/local/bin/elm
npm ERR! Move it away, and try again.

I think it is complaining about my Elm 0.19 installation – don’t want to break that.

Do you have advice on how I should proceed?

I think if you already have elm installed you can just

npm install --global prettier prettier-plugin-elm

(i.e. just install the non-elm packages)

Hello @jwoLondon! I was able to install litvis with your help. All good so far except
that I can’t seem to import packages, as in the following, which gives an error (on import).

Examples


elm:
dependencies:
jxxcarlson/hex: latest

message : String
message = "Hello World!"
import Hex exposing(..)
str = "abcdefghi"
Hex.stringBlocks 4 str

You need to place any import statements before the Elm function definitions. Also, statements should all be inside functions, so the following should work:

---
elm:
  dependencies:
    jxxcarlson/hex: latest
---

```elm {raw}
import Hex exposing (..)


message : String
message =
    "Hello World!"


message2 : List String
message2 =
    Hex.stringBlocks 4 "abcdefghi"
```

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.