**hestia** is a small, functional language built for scripting. This is a short, incomplete walkthrough of the language. Feel free to try things in the REPL below:

hestia>

hestia has no user-defined data types. While this limits expressive power, it also limits complexity. Here are the current data types in hestia, with examples:

- integer -
`145, 0, -58212`

- float -
`145.0, 0.18248, -58212.888`

- string -
`"hello", "", "---\n----"`

- symbol -
`'aaaa, 'test-symbol, 'HELLO`

- boolean -
`true, false`

- list -
`[], [1 2 3], [true 'a [1]]`

- map -
`{}, {a: 23}, {'a: 23}, {2: "a" "test": true}`

- function -
`{|x| (add 1 x)}, {||}, {|a b c| (add a b c) }`

- option -
`(none), (some 123), (some [1 2 true])`

Note that commas in hestia are whitespace, so `(eq? 1000 1,000)`

, `(eq? {a: 1 b: 2} {a: 1, b: 2})`

, and `(eq? [1, 2, 3] [1 2 3])`

all evaluate to `true`

.

Also note that `{a: 1}`

is syntactic sugar (shorthand) for `{'a: 1}`

, a map that contains one key-value pair: from the symbol `'a`

to the integer `1`

.

**All data structures in hestia are immutable.**There are no functions that modify data structures in-place. Instead, functions return NEW data structures.

To globally name a value, use `(def x 100)`

. Later code can then reference `x`

.

To locally name a value, use `(let ([x 100]) x)`

. Only code within the `let`

expression can reference such names.

Global functions are just named functions, e.g., `(def add1 {|x| (add 1 x)})`

Probably the most important functions in hestia are `lmap`

and `lreduce`

. The `l`

stands for list. For instance, to add 1 to every integer in a list, you call `(lmap add1 [1 2 3])`

which evaluates to `[2 3 4]`

. `lmap`

takes a function and a list as its arguments, and is defined as follows:

```
(def lmap { |f list|
(if (empty? list)
[]
(cons (f (first list))
(lmap f (rest list))))})
```

Let's break this down. First, an `(if test then else)`

expression checks if `test`

is `true`

and if so, evaluates to `then`

; if false, it evaluates to `else`

.

Thus, `lmap`

first checks if the given list is empty, and if so, it simple returns an empty list. If not, it calls the given function on the first element of the list, and then recursively calls `lmap`

on the rest of the list. It then uses `cons`

, which takes a value and a list and returns a new list with that value prepended to the list, to return a new updated list.

However, all functions in hestia are automatically curried. To show what this means, consider that we could write the adding `lmap`

equivalently as follows: `(lmap (add 1) [1 2 3])`

because `add`

requires at least 2 arguments---when it receives 1 argument, it returns a function that takes (at least) 1 argument and adds 1 to it.

To sum all integers in a list, use `(lreduce 0 add [1 2 3])`

. `lreduce`

takes a "base" value, a function, and a list. Here's the source:

```
(def lreduce { |acc f list|
(if (empty? list)
acc
(lreduce (f acc (first list)) f (rest list)))})
```

In our case, `lreduce`

adds "pairs" of integers, with the first pair being `0`

and `1`

, the second pair being the sum of the first pair and `2`

, and so on.

© semaj 2023