# A Command Line Interpreter in Elm

**URL:** <https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457>\
**Category:** Show and Tell\
**Created:** [April 6, 2020, 5:54pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457 "2020-04-06T17:54:19Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jxxcarlson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jxxcarlson/32/866_2.png) [@jxxcarlson](https://discourse.elm-lang.org/u/jxxcarlson)\
**Post date:** [April 6, 2020, 5:54pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/1 "2020-04-06T17:54:19Z")

</div>

Hi All, I’d like to report on building and using command-line interpreter (CLI) that talks to Elm code. The bottom line is that is that it is quite easy to do using `Platform.Worker`. One writes a headless Elm  
program that communicates via ports with a 17-line Javascript program `cli.js`. The javascript program uses the Node `repl` module to provide a convenient user interface. To run the CLI, just say `node cli.js`. The code is on [GitHub](https://github.com/jxxcarlson/elm-command-interpreter).

(This post expands on an [earlier article](https://discourse.elm-lang.org/t/platform-worker-example/5074) on the subject `Platform.Worker`.)

## A Skeleton App

What I will describe here is a skeleton CLI that I derived from something I am using to do real work on another project. It has a simple structure that can be easily bent to other ends. Below is the help screen, which says pretty much all there is to say about how to use the program.

 ![help](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/d/d2b7b5b935ec1ea66e2f112ea19a94276e3adbdb.png)

And here is a short session:

```auto
> add 2 3 -- the result is stored register M
5
> mul 4 -- only one operand given, so we use the contents of M for the other
20
> pow 1.1 10 -- exponential growth -- beware!
2.5937
> sto a -- store the contents of register M in register A
M > A
> r a -- read the contents of A
A: 2.5937
> log 10 23 -- compute the base-10 logarithm of 23
1.3617
> rcl a -- recall the contents of A, store in M
A > M
> r m. -- yes, it is there
M: 2.5937
ETC.

```

## RPN Version (Note added)

There is now a stack-based version of the calculator. This screenshot explains it:

 ![Screen Shot 2020-04-10 at 23.30.22](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/4/4283e5c4fba1543afa006c8d14ebdcd3e2dad2f8.png)

The [Github Repo](https://github.com/jxxcarlson/elm-command-interpreter) now has three branches: master, original, and stack, so you can look at the code that interests you. Generally speaking, master = stack.

## Code

The organization of the code is pretty well described in the [README](https://github.com/jxxcarlson/elm-command-interpreter) so I won’t repeat it here. Better just to look at it if you are interested. Here is a birds-eye-view:

```auto
-------------------------------------------------------------------------------
File blank comment code
-------------------------------------------------------------------------------
src/Command.elm 99 10 212
src/Main.elm 27 3 71
src/Model.elm 8 0 24
src/ArgList.elm 14 1 19
src/cli.js 6 3 17
-------------------------------------------------------------------------------
SUM: 154 17 343
-------------------------------------------------------------------------------

```

To customize things, you will need to do two things. First is to  
adapt the dispatcher function in `Main.elm`:

```auto
executeCommand : Model -> String -> ArgList -> String -> ( Model, Cmd Msg )
executeCommand model cmd args input =
    case cmd of
        "add" ->
            Command.op model (+) args

        "mul" ->
            Command.op model (*) args

        ...

        "exp" ->
            Command.f1 model (\x -> e ^ x) args

        "ln" ->
            Command.f1 model (logBase e) args

        "pow" ->
            Command.f2 model (\a b -> a ^ b) args

      ...

```

The second is to implement code in `Command.elm` that carries out your commands. This is the biggest file in project and is mostly specific to the particular functions of the program.

## Addendum

The skeleton app described above is a distillation of work on another project. The CLI can read source text in some mythical markup language like this:

```auto
$ run cli
> .load source/t1 -- load source into register M
> d -- display it

```

 ![source](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/1/1769d59fdda09630e5edfbdfc2b290d42f8c1070.jpeg)

Now parse it and display a representation of the parse tree:

![parsetree](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/f/faa37929fb7633193c5fb61f8b21679c5de8aa21.png)

A node in the tree takes up a single line, with the symbol • standing for newlines. The depth of a node in the parse tree is indicated both by the displayed integer and by indentation,

---

<div class="post-metadata">

**Author:** ![DullBananas](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dullbananas/32/3709_2.png) [@DullBananas](https://discourse.elm-lang.org/u/DullBananas)\
**Post date:** [April 6, 2020, 7:33pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/2 "2020-04-06T19:33:48Z")

</div>

how is it different from elm repl? im a bit confused as to what this even does

---

<div class="post-metadata">

**Author:** ![jxxcarlson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jxxcarlson/32/866_2.png) [@jxxcarlson](https://discourse.elm-lang.org/u/jxxcarlson)\
**Post date:** [April 6, 2020, 9:10pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/3 "2020-04-06T21:10:26Z")

</div>

Hi, the Elm repl gives you a way of running small bits of Elm code without a web browser. A command-line interpreter (CLI) as in the example in this article doesn’t run elm code directly, and what you type into it is not Elm code. For example, `sto a` means store the contents of register M in register A. The phrase `sto a` is not part of the Elm language, even though it causes Elm code to do something.

---

<div class="post-metadata">

**Author:** ![jigargosar](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jigargosar/32/79_2.png) [@jigargosar](https://discourse.elm-lang.org/u/jigargosar)\
**Post date:** [April 8, 2020, 8:31am UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/4 "2020-04-08T08:31:25Z")

</div>

Thanks a lot for taking the time out to extract code from your real world project, and sharing it with us.

The knowledge gained from looking at the source code is invaluable.

Most of the time I keep wondering how others would model a problem domain that I am struggling with. And what alternatives would look like.

> [@jxxcarlson](#):
>
> What I will describe here is a skeleton CLI that I derived from something I am using to do **real work on another project**.

Please do share any content that has been practically useful. Your efforts are really appreciated.

---

<div class="post-metadata">

**Author:** ![jxxcarlson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jxxcarlson/32/866_2.png) [@jxxcarlson](https://discourse.elm-lang.org/u/jxxcarlson)\
**Post date:** [April 10, 2020, 2:13pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/5 "2020-04-10T14:13:02Z")

</div>

I’ve added a stack-based RPN version of the calculator in the stack branch of the repo. The register-based version is the original branch:

- [stack branch](https://github.com/jxxcarlson/elm-command-interpreter/tree/stack)
- [original branch](https://github.com/jxxcarlson/elm-command-interpreter/tree/original)

 ![Screen Shot 2020-04-10 at 16.10.43](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/7/7be76d5fdf1e70510f089ff9f027e3ef1f7d134c.png)

Here is the help screen:

 ![Screen Shot 2020-04-10 at 16.12.13](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/4/4ada694824c02c960469bba56437a8f0663fabff.png)

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [April 20, 2020, 2:13pm UTC](https://discourse.elm-lang.org/t/a-command-line-interpreter-in-elm/5457/6 "2020-04-20T14:13:15Z")

</div>

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