Command Line Interpreters in Elm, Part I

Image for post
Image for post
Elm RPN calculator on the command-line

A one-shot command-line program

$ node src/cli.js 33Input:  33
Output: 100
Image for post
Image for post
Wiring diagram for headless Elm apps

The Javascript Program

// File: cli.js// Link to compiled Elm code main.js
var Elm = require('./main').Elm;
var main = Elm.Main.init();

// Get data from the command line
var args = process.argv.slice(2);
var input = parseInt(args[0])
console.log("\n Input: ", input)

// Send data to the worker
main.ports.get.send(input);

// Get data from the worker
main.ports.put.subscribe(function(data) {
console.log(" Output: " + JSON.stringify(data) + "\n");
});

The Elm Program

case msg of
Input input -> ( model, put (transform input))
port module Main exposing (main)

import Platform exposing (Program)

type alias InputType = Int
type alias OutputType = Int

port get : (InputType -> msg) -> Sub msg
port put : OutputType -> Cmd msg

main : Program Flags Model Msg
main =
Platform.worker
{ init = init
, update = update
, subscriptions = subscriptions
}

type alias Model = ()
type Msg = Input Int
type alias Flags = ()


init : Flags -> ( Model, Cmd Msg )
init _ = ( (), Cmd.none )

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Input input -> ( model, put (transform input))

subscriptions : Model -> Sub Msg
subscriptions _ =
get Input

{- Below is the input-to-output transformation.
It could be anything. Here we have something
simple for demonstration purposes.
-}

transform : InputType -> OutputType
transform k =
case modBy 2 k == 0 of
True -> k // 2
False -> 3*k+ 1

A REPL (Read Eval Print Loop)

$ node src/repl.js
> 33
100
> 100
50
> 50
25
> 25
76
// File: src/repl.jsconst repl = require('repl');

// Link to Elm code
var Elm = require('./main').Elm;
var main = Elm.Main.init();

// Eval function for the repl
function eval(input, _, __, callback) {
main.ports.put.subscribe(
function putCallback (data) {
main.ports.put.unsubscribe(putCallback)
callback(null, data)
}
)
main.ports.get.send(Number(input))
}

repl.start({ prompt: '> ', eval: eval });

References

Written by

jxxcarlson on elm slack, http://jxxcarlson.github.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store