dolt icon indicating copy to clipboard operation
dolt copied to clipboard

Super REPL

Fun with REPLs

npm install && npm start
open http://localhost:8000/

Language

The language available in the REPL has a syntax largely taken from JavaScript, with slightly different semantics. The JavaScript-like essentials are:

// values
1, 'foo', true // number, string, boolean literals
{foo: 1}       // object literal
[1,2,3]        // array literal

// arithmetic
1 + 2 - 3 / 4 * 5   // operators
n += 1  // in-place arithmetic
n < 3   // comparison

// other stuff you might expect
var x = 1      // assignment
foo.bar       // field access
frob(1, 'foo')        // procedure call

There are no prototypes and no dynamically-scoped this variable; however, fields may be procedures, and some of the built-ins look like methods.

Sequences and comprehensions

Sequences are an addition; in general these are produced by built-ins (e.g., range just below) and comprehensions, and are lazy[1]. Arrays will be lifted to sequences when treated as a sequence; sequences may be indexed, in which case they are evaluated up to the element given.

The built-in range produces a sequence starting at its first argument and ending less than or equal to its second argument, incrementing by its third argument (or 1 if not supplied).

range(0, 10, 2) // => 0,2,4,6,8,10 in a sequence
range(0, 10, 3) // => 0,3,6,9
range(0, 10)[2] // => 2

Sequences support map, where, and concat operations, all returning lazy sequences. The first two take, in argument position, an expression to be applied to each element:

[1,2,3].map(_ + 1)
range(0, 10).where(_ < 5)

The variable _ is bound to the element being considered. If the element is an object, its field names will also be bound when the expression is evaluated:

[{foo: 1}, {foo: 2}].map(foo + 1)

The name to be bound may also be supplied, in which case field access must be explicit:

[{foo: 1}, {foo: 2}].map(x, x.foo + 1)

The result is always a sequence, so map and where may be chained together:

range(0, 10).map(_ + 1).where(_ < 5)

Comprehensions represent sequences by specifying a generating expression, a map expression, and optionally a where expression:

[_ + 1 for [1,2,3]]
[x + 1 for x in [1,2,3]]
[x + 1 for x in range(0, 10) if x < 5]

These may be nested, in which case the inner generation expression and where expression have both the outer and inner elements bound:

[x + y for x in range(0, 10); y in range(0, x) if x * y < 10]

String interpolation

Strings with double quotes are treated as patterns to be interpolated. Expressions within curly braces in such a string are evaluated in the local environment:

"The answer is {2 + 2}" // => 'The answer is 4'

These can be used in maps and comprehensions, of course:

  ["Foo = {foo}" for [{foo: 1}, {foo: 2}]]

Object construction

There is shorthand for constructing objects in which the field names match variable names; this is especially useful in maps and comprehensions:

var foo = 1; {foo} // => {foo: 1}
[{bar} for [{foo: 1, bar: 2}, {foo: 2, bar: 3}]]

[1] They are "even streams" as described (albeit in the context of Scheme) at http://srfi.schemers.org/srfi-41/srfi-41.html.