Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/obaraelijah/x9

Speedy self-documenting lisp in Rust.
https://github.com/obaraelijah/x9

lisp rust

Last synced: 7 days ago
JSON representation

Speedy self-documenting lisp in Rust.

Awesome Lists containing this project

README

        

#+AUTHOR: Elijah Samson

* The x9 Programming Language

x9 is a lisp I built to better understand programming languages and interpreters.

The standard library is being written in either x9 or rust for performance.

** Features
*** Usual Lispy Goodness

You have brackets. Lots of brackets. And lists. And functions.

*** Self-documenting

The goal is to have every function describe itself, so you can live in the repl.

Use the =doc= function on a symbol to see it's documentation:

#+begin_example
>>> (print (doc foreach))
Eagerly apply the given function to a sequence or list.
Example:
(foreach
(fn (x) (println x))
(range 20)) ; prints 0 to 20. Returns ().

(foreach
(fn (x) (println x))
(take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096
#+end_example

The general goal is to be as helpful as possible. So stacktraces include more
information than you'd usually get, such as arguments.

For example, the following program will fail:

#+begin_src elisp
(defn bottom (x) (% x 2))
(defn middle (x) (bottom x))
(defn top () (middle "a"))
(top)
#+end_src

And give this helpful stacktrace:

#+begin_example
Error: BadTypes

Stacktrace:
- Remainder requires left and right are num types, was given "a" % 2
- Error in Fn<%, 2, [ ]>, with args ("a" 2)
- Error in Fn, with args ("a")
- Error in Fn, with args ("a")
- Error in Fn, with args ()
#+end_src
#+end_example

*** Convenient FFI

x9 offers easy and convenient embedding into other rust programs.

#+begin_src rust
use x9::ffi::{x9Interpreter, ForeignData};

let interpreter = x9Interpreter::new();
let res = interpreter.run_program::("(+ 1 1)").unwrap();
assert_eq!(res, 2);
#+end_src

You can interface your own types in x9 with the =ForeignData= trait, and
add foreign functions into the interpreter. To maximize convenience foreign functions
are typed in terms of their own datatypes - not x9's Expr type.

#+begin_src rust
let interpreter = x9Interpreter::new();
let my_sum_fn = |args: Vec| Ok(args.iter().sum());
// Add the my-sum to interpreter
interpreter.add_function("my-sum", 1, Arc::new(my_sum_fn));

// And verify we get u64 with value 6 out of it.
assert_eq!(interpreter.run_program::("(my-sum 1 2 3)").unwrap(), 6);
#+end_src

More interesting is the fact that functions added to the interpreter
in a strongly typed way, allowing us to mix types!

#+begin_src rust
// Recall that my-sum is a Fn(Vec) -> u64
let string_res = interpreter.run_program::("(my-sum 1 2 3)").unwrap();
// And we get a string out it!
assert_eq!(string_res, "6".to_string());
#+end_src

The reason it works is we embed the type information into the function
added to the interpreter, and x9's =Expr= type acts as a bridge between types.

For more info see the =ffi.rs= example in the examples folder!

You can run the example with:

#+begin_example
cargo run --example ffi
#+end_example

*** Speedy Iterators

Certain constructs like =(range)= and =map= are backed by lazy iterators, making them pretty fast.

** Examples

*** Fibonacci Numbers

We can print the first hundred fibonacci numbers in 14 milliseconds:

#+begin_src elisp
;; fib.x9
;; Run with: x9 fib.x9

;; Map (l, r) -> (r, l + r)

(defn fib-step (x)
(bind ((l r) x) ^(r (+ l r))))

;; Reduce (0 1) `num` times using fib-step to
;; generate the `num`'th fibonacci number

(defn fib (num)
(nth 0 (reduce
fib-step
(tuple 0 1)
(range num))))

;; Print one hundred fibonacci numbers
;;
;; Note: (take 100 (map fib (range)))
;; is an iterator which maps to Rust's iterators which
;; makes them very fast. No weird intermediate allocations.

(println (time (foreach
println
(take 100 (map fib (range))))))
#+end_src

Outputs:

#+begin_example
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
...truncated...
83621143489848422977
135301852344706746049
218922995834555169026
#+end_example

** More Features
*** Dynamic Records and Syntactic Sugar

A recent addition to the language is the =defrecord= and =defmethod= functions,
which allow you to define records in =x9= and add methods to the them respectively.

Here's an example of defining =Vec3=, and a way to add them together:

#+begin_src lisp
;; Define a record
(defrecord Vec3 "Three dimensional vector" x y z)

;; Add a method to it
(defmethod Vec3 +
"Add two vectors together"
(other)
(Vec3
(+ other.x self.x)
(+ other.y self.y)
(+ other.z self.z)))
#+end_src

This lets us encapsulate data, and access it in a nice structured way.

#+begin_src lisp
;; Instantiate a Vec3
(def my-vector (Vec3 1 1 1))

;; Call the + method
(.+ my-vector my-vector) ;; Record
#+end_src

The process of adding this support added two
new ways to interact with expressions - callable Records and field-access-sugar

**** Callable Records

To make record construction nice, you can treat records defined with =defrecord= as constructor functions:

#+begin_example
>>> (defrecord Point x y)
Record
>>> (Point 0 0)
Record
#+end_example

**** Record Field Syntactic Sugar

By default, fields of a record are treated as zero-arity methods on that record, with =self= being inserted with method_call syntax.

This meant that this got old after a while:

#+begin_example
(+ (.x self) (.x other))
#+end_example

So I added some sugar in the form of =self.x=:

#+begin_example
>>> (defrecord Point x y)
>>> (def origin (Point 0 0))
>>> origin.x
0
#+end_example

It works in a recursive way if you have deeply nested fields.

#+begin_example
>>> (defrecord Point x y)
>>> (defrecord Space origin)
>>> (def space (Space (Point 0 0)))
>>> space.origin
Record
>>> space.origin.x
0
>>> space.origin.y
0
#+end_example

The syntax immediately evaluates, as it gets transformed a nested list of function calls:

#+begin_example
space.origin.y ;; (.y (.origin space))
#+end_example

You can do some tricks with this, like this:

#+begin_src lisp
(def file (fs::open "input.txt"))
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(def captures (.captures re file.read_to_string))
#+end_src

Zero arity functions can also be referenced:

#+begin_example
>>> (def v (Vec3 1 1 1))
nil
>>> v.scale
Fn; #args=1>, 0, [ ]>
>>> (v.scale 3)
Record
>>> v.length
1.73205080
#+end_example

*** Anonymous Function Syntactic Sugar

You can easily create anonymous functions with =#(...)=. Here's an example:

#+begin_src lisp
(filter #(< $1 10) (range 100)) ;; (0 1 2 3 4 5 6 7 8 9)

(map #(+ 10 $1) (range 10)) ;; (10 11 12 13 14 15 16 17 18 19)
#+end_src

Fields are labelled =$1, $2, ...=.

** Language Description

x9 is a quirky lisp which sort of evolved naturally. It has the following data-types:

#+begin_src rust
pub enum Expr {
Num(Num),
Integer(Integer),
Symbol(Symbol),
List(Vector),
Function(Arc),
Nil,
String(String),
Quote(Vector),
Tuple(Vector),
Bool(bool),
LazyIter(IterType),
Dict(Dict),
Record(crate::records::RecordType),
}
#+end_src

*** =Num=

Numbers in x9 are arbitrary precision =BigDecimal= types backed by the =bigdecimal= crate.

Example:
#+begin_example
0
0.0
1.1
1000000000000000000
#+end_example

*** =Integer=

A fast-path for integer heavy calculations.
If you can avoid non-whole numbers this is substantially faster than the =Num= type.

Example:
#+begin_example
1
2
-5
#+end_example

*** =Symbol=

Symbols are references to some object in the symbol table. They can't contain quotes or brackets.

Example:
#+begin_example
+
sort
doc
#+end_example

*** =List=

A list is a sequential collection of values. When evaluated, the first argument is called as a function
with the rest of the elements as arguments.

Example:
#+begin_example
(+ 1 2)
(println "hello world!")
#+end_example

*** =Function=

A function is a type defined by the =fn= or =defn= keywords. They accept a variable number
of arguments and carry a local scope. Variables shadow each other, and functions will close over arguments.

Example:
#+begin_src elisp
(defn is-odd?
(x)
(= 1 (% x 2))) ; add function is-odd? to symbol table

(map
(fn (num) (* num num)) ; anon func
(range 20))

(defn not=
(& args) ; excess variables can be captured into a list
(not (apply = args)))
#+end_src

*** =Nil=

Null type. Usually equal to an empty list.

*** =String=

A UTF-8 string of characters between two quotes: "hello world!"

*** =Quote=

An unevaluated list. When evaluated, it turns into a list.

Has special syntax: ='(1 2 3)=
And a keyword: =(quote 1 2 3)=

*** =Tuple=

Same thing as a list, but always evals to itself.

Has special syntax: =^(1 2 3)=
And a keyword: =(tuple 1 2 3)=

*** =Bool=

Classic boolean. True or false.

Example:
#+begin_example
true
false
(= 1 0) ;; false
#+end_example

*** =LazyIter=

A sequence of values backed by a Rust iterator. These are useful for working
with infinite sequences.

Currently, =map=, =filter=, =take=, and =range= can yield lazy iterators.

They are evaluated with =doall= to make a list or =foreach= to operate on it.

Example:

#+begin_example
(doall (take 5 (map inc (range)))) ; (1 2 3 4 5)
; Or
(foreach
println
(take 5 (map inc (range)))) ; prints one through five
#+end_example

*** =Dict=

Classic immutable dictionary. This is certainly a work in progress.

Example:
#+begin_example
(def foo (dict "key1" "value1" 3 4))

(get foo 3) ;; 4
(get foo "key1") ;; "value1"

(set foo 5 6) ;; {"key1": "value1", 3: 4, 5: 6}
;; This does not mutate `foo`!
(get foo 5) ;; nil
#+end_example

*** =Record=

Objects in =x9=. See the [[https://github.com/dpbriggs/x9#dynamic-records-and-syntactic-sugar][record section above]].

** Standard Library Reference

The x9 language has self-documenting features. The standard library reference is generated
with the script below, which =org-mode= pastes into the list below:

#+begin_src elisp
(defn pretty-print
"Format doc strings into something org-mode will agree with."
(x)
(bind
((sym docu) x)
(do
(println "*** =" sym "=")
(println "")
(println "#+BEGIN_SRC elisp")
(println docu)
(println "#+END_SRC")
(println ""))))

(foreach
pretty-print
(zip (all-symbols) (map doc (all-symbols))))
#+end_src

#+begin_src sh :results output raw :format org :exports results
cargo run --release -- gen_docs.x9
#+end_src

#+RESULTS:
*** =+=

#+BEGIN_SRC elisp
Add two items together. Concatenates strings, lists, and tuples.
Example: (+ 1 1 1) ; 3
Example: (+ "Hello " "World") ; "Hello World"

#+END_SRC

*** =-=

#+BEGIN_SRC elisp
Subtracts all items from the first. Only works with Nums.
Example: (- 2 1 1) ; 0

#+END_SRC

*** =*=

#+BEGIN_SRC elisp
Multiply all items against the first. Works with Nums and (String Num*)
Example: (* 1 2 3) ; 6
(* "abc" 3) ; "abcabcabc"

#+END_SRC

*** =%=

#+BEGIN_SRC elisp
Take the remainder of the first item against the second.
Example: (% 4 2) ; 0
#+END_SRC

*** =/=

#+BEGIN_SRC elisp
Divide the first element by the rest.
Example: (/ 8 2 2 2) ; 1

#+END_SRC

*** =sqrt=

#+BEGIN_SRC elisp
Take the square root of a number. There's minor precision loss as it's way faster to convert to floats internally over using a bigdecimal.
Example: (sqrt 9) ; 3

#+END_SRC

*** ===

#+BEGIN_SRC elisp
Test if all items are equal.
Example: (= 1 1) ; true
(= 1) ; true

#+END_SRC

*** =<=

#+BEGIN_SRC elisp
Test if the first item is strictly smaller than the rest.
Example: (< 0 1 2) ; true
#+END_SRC

*** =<==

#+BEGIN_SRC elisp
Test if the first item is smaller or equal to the rest.
Example: (<= 0 0 0.05 1) ; true
#+END_SRC

*** =>=

#+BEGIN_SRC elisp
Test if the first item is strictly greater than the rest.
Example: (> 10 0 1 2 3 4) ; true
#+END_SRC

*** =>==

#+BEGIN_SRC elisp
Test if the first item is greater than or equal to the rest.
Example: (>= 10 10 5) ; true
#+END_SRC

*** =inc=

#+BEGIN_SRC elisp
Increment the given number.
Example:
(inc 2.2) ;; 3.3
(inc 1) ;; 2

#+END_SRC

*** =dec=

#+BEGIN_SRC elisp
Decrement the given number.
Example:
(dec 2.2) ;; 3.3
(dec 1) ;; 2

#+END_SRC

*** =pow=

#+BEGIN_SRC elisp
Raise a number to an exponent.
Example:
(pow 2 3) ;; 8
(pow 10 3) ;; 1000

#+END_SRC

*** =floor=

#+BEGIN_SRC elisp
Floor a number.
Example:
(floor 5.5) ;; 5.5

#+END_SRC

*** =int=

#+BEGIN_SRC elisp
Create an integer from the input.

Example:
(int 3.2) ;; 3

#+END_SRC

*** =not=

#+BEGIN_SRC elisp
Invert the bool. true becomes false and vice-versa.
#+END_SRC

*** =or=

#+BEGIN_SRC elisp
logical or.
#+END_SRC

*** =and=

#+BEGIN_SRC elisp
logical and.
#+END_SRC

*** =xor=

#+BEGIN_SRC elisp
logical xor.
#+END_SRC

*** =ident=

#+BEGIN_SRC elisp
Identity function. Returns what you give it.
#+END_SRC

*** =quote=

#+BEGIN_SRC elisp
Transforms the given input into a quote. Usually you will want to use the '(1 2 3) syntax.
#+END_SRC

*** =symbol=

#+BEGIN_SRC elisp
Turn a string into a symbol
#+END_SRC

*** =str=

#+BEGIN_SRC elisp
Make a string
#+END_SRC

*** =bool=

#+BEGIN_SRC elisp
Coerce a value to bool. In general if a collection is non-empty, it is true. The len method is called on Records
#+END_SRC

*** =print=

#+BEGIN_SRC elisp
Print the given argument WITHOUT a newline.
#+END_SRC

*** =println=

#+BEGIN_SRC elisp
Print the given argument WITH a newline.
#+END_SRC

*** =input=

#+BEGIN_SRC elisp
Get user input from stdin
#+END_SRC

*** =split=

#+BEGIN_SRC elisp
Split a string with some substring.
Example:
>>> (split "," "hello, world")
(tuple "hello" " world")

#+END_SRC

*** =replace=

#+BEGIN_SRC elisp
Replace a substring in a string with some other string.
Example:
>>> (replace "abc" "OwO" "abc def")
"OwO def"
#+END_SRC

*** =ident-exists=

#+BEGIN_SRC elisp
Returns true if a given symbol exists in the interpeter
#+END_SRC

*** =eval=

#+BEGIN_SRC elisp
Eval an expression.
Example (in repl):
>>> '(+ 1 2)
(+ 1 2)
>>> (eval '(+ 1 2))
3
#+END_SRC

*** =parse=

#+BEGIN_SRC elisp
Parse an expression.
Example (in repl):
>>> (parse "(+ 1 2)")
#+END_SRC

*** =def=

#+BEGIN_SRC elisp
Associate a given symbol with a value. Overwrites local variables.
Example:
>>> (def a 3)
>>> a
3

#+END_SRC

*** =cond=

#+BEGIN_SRC elisp
Branching control flow construct. Given an even list of [pred then], if `pred` is true, return `then`.
Example:
(def input 10)
(cond
(= input 3) (print "input is 3")
(= input 10) (print "input is 10")
true (print "hit base case, input is: " input))

#+END_SRC

*** =loop=

#+BEGIN_SRC elisp
Not done yet. Loop in a weird way. Repeatedly runs the body until (break) is called.
#+END_SRC

*** =match=

#+BEGIN_SRC elisp
Branching control flow construct. Given an item and an even list of [value then], if `item` == `value`, return `then`.
Example:
(def input 10)
(match input
3 (print "input is 3")
10 (print "input is 10")
_ (print "hit base case, input is: " input))

#+END_SRC

*** =if=

#+BEGIN_SRC elisp
Branching control flow construct. Given pred?, then, and else, if pred? is true, return then, otherwise, else.
Note: Does not evaluate branches not taken.
Example:
(def input 10)
(if (= input 10)
(print "input is 10!")
(print ":[ input is not 10"))

#+END_SRC

*** =shuffle=

#+BEGIN_SRC elisp
Shuffle (randomize) a given list.
Example:
>>> (shuffle (range 10))
(6 3 2 9 4 0 1 8 5 7)

#+END_SRC

*** =go=

#+BEGIN_SRC elisp
Run a function in a new thread. Example:
(go (fn ()
(do
(sleep 2)
(println "from another thread!"))))

;; After two seconds, something is printed
#+END_SRC

*** =chan=

#+BEGIN_SRC elisp
Make a channel. Returns a tuple of (writer, reader). Example:
(bind
((w r) (chan))
(do
(go (fn () (print-recv r)))
(.send w "in bind context 1")
(sleep 1)
(.send w "in bind context 2")
(.close w)
))

;; Two things are printed.
#+END_SRC

*** =random_bool=

#+BEGIN_SRC elisp
Randomly return true or false.
#+END_SRC

*** =random_int=

#+BEGIN_SRC elisp
Randomly return an integer between lower and upper.

Example:
(random_int 0 10) ;; Returns a num between 0 and 10 (exclusive)
#+END_SRC

*** =panic=

#+BEGIN_SRC elisp
Abort the program printing the given message.

Example: (panic "goodbye") ; kills program

Your console will print the following:

thread 'main' panicked at 'goodbye', src/stdlib.rs:216:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

... and the interpreter will stop.

#+END_SRC

*** =primes=

#+BEGIN_SRC elisp
Prime numbers less than `n`.
#+END_SRC

*** =divisors=

#+BEGIN_SRC elisp
Divisors of `n`. Example:
(divisors 20) ;; ^(1 2 4 5 10 20)
#+END_SRC

*** =clrf=

#+BEGIN_SRC elisp
HACK! Returns
as the parser is buggy atm.
Example: (clrf) ; "
"
#+END_SRC

*** =timestamp=

#+BEGIN_SRC elisp
Returns a unix timestamp.
Example: (timestamp "%b %-d, %-I:%M") ; "Jul 2, 5:15"
#+END_SRC

*** =name-of=

#+BEGIN_SRC elisp
Returns the name of the object.
Example: (name-of +) ; "+"
#+END_SRC

*** =sleep=

#+BEGIN_SRC elisp
Sleep for n seconds.
Example: (sleep 10) ; sleep for 10 seconds.
#+END_SRC

*** =type=

#+BEGIN_SRC elisp
Return the type of the argument as a string.
Example: (type "hello") ; str
#+END_SRC

*** =doc=

#+BEGIN_SRC elisp
Return the documentation of a symbol as a string.
Example: (doc doc) ; Return the documentation of a symbol as a...
#+END_SRC

*** =err=

#+BEGIN_SRC elisp
Return an error with a message string.
Example: (err "Something bad happened!") ; return an error
#+END_SRC

*** =all-symbols=

#+BEGIN_SRC elisp
Return all symbols defined in the interpreter.
#+END_SRC

*** =include=

#+BEGIN_SRC elisp
Include a file into the interpreter.
#+END_SRC

*** =map=

#+BEGIN_SRC elisp
Apply a function to each element of a sequence and return a list.
Example: (map inc '(1 2 3)) ; (2 3 4)

#+END_SRC

*** =mapt=

#+BEGIN_SRC elisp
Apply a function to each element of a sequence and return a tuple.
Example: (map inc '(1 2 3)) ; ^(2 3 4)

#+END_SRC

*** =->=

#+BEGIN_SRC elisp
DOCS TBD
#+END_SRC

*** =inline_transform=

#+BEGIN_SRC elisp
Given a list of data and another of functions, apply each function pairwise onto the list.
Example:

(defn adder-maker (x) (fn (y) (+ x y)))

(inline_transform
'(1 1 1)
(list (adder-maker 1) (adder-maker 2) (adder-maker 3))) ;; ^(2 3 4)

#+END_SRC

*** =foreach=

#+BEGIN_SRC elisp
Eagerly apply the given function to a sequence or list.
Example:
(foreach
(fn (x) (println x))
(range 20)) ; prints 0 to 20. Returns ().

(foreach
(fn (x) (println x))
(take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096

#+END_SRC

*** =filter=

#+BEGIN_SRC elisp
Retain elements in a sequence according to a predicate.
Example:
(defn is-odd (x) (= 1 (% x 2)))
(filter is-odd (range 20)) ; outputs (1 3 5 7 9 11 13 15 17 19)

#+END_SRC

*** =any=

#+BEGIN_SRC elisp
Ask whether a predicate is true in some sequence. Short circuits.
#+END_SRC

*** =all=

#+BEGIN_SRC elisp
Ask whether a predicate is true for every element of a sequence. Short circuits.
#+END_SRC

*** =lazy=

#+BEGIN_SRC elisp
Turn a list into a lazy sequence. Useful for building complex iterators over some source list.
#+END_SRC

*** =skip=

#+BEGIN_SRC elisp
Skip some amount in a lazy iterator.
#+END_SRC

*** =product=

#+BEGIN_SRC elisp
Cartesian Product every list passed in.
Example:
>>> (doall (product '(0 1) '(0 1) '(0 1)))
(
(tuple 0 0 0)
(tuple 1 0 0)
(tuple 0 1 0)
(tuple 1 1 0)
(tuple 0 0 1)
(tuple 1 0 1)
(tuple 0 1 1)
(tuple 1 1 1)
)

#+END_SRC

*** =apply=

#+BEGIN_SRC elisp
Apply a function to a given list.
(def my-list '(1 2 3))
(apply + my-list) ; outputs 6

#+END_SRC

*** =do=

#+BEGIN_SRC elisp
Evaluate a sequence of expressions and return the last one.
Example:
(defn complex-fn (x)
(do
(print "current state: " x)
(+ x x)))

#+END_SRC

*** =partial=

#+BEGIN_SRC elisp
;; Construct a partial function.

;; Example:
(defn foobar (x y z) (+ x y z))

(def part (partial foobar 1 2))
(part 3) ;; 6

((partial foobar 1) 0 -1) ;; 0

(partial + 1) ;; Fn; remaining=0>, 0, [ ]>

#+END_SRC

*** =comp=

#+BEGIN_SRC elisp
Compose given functions and return a new function. NOT IMPLEMENTED YET!
#+END_SRC

*** =reduce=

#+BEGIN_SRC elisp
Reduce (fold) a given sequence using the given function. Reduce is multi-arity, and will accept an `init` parameter.
Example:
(reduce + '(1 2 3)) ; 6
(reduce + 100 '(1 2 3)) ; 106

#+END_SRC

*** =fn=

#+BEGIN_SRC elisp
Create a anonymous function.
Example:
(fn (x) (* x 2)) ; Fn

#+END_SRC

*** =defn=

#+BEGIN_SRC elisp
Define a function and add it to the symbol table. Supports doc strings.
Example:
(defn is-odd? (x) (= 1 (% x 2)))
(defn get-odd-numbers
"Extract the odd numbers out of the given sequence `x`"
(x)
(filter is-odd? x)) ; for fun, try (doc get-odd-numbers)

#+END_SRC

*** =anon-fn-sugar=

#+BEGIN_SRC elisp
Create an anonymous, automatic binding function. You normally want to use the #(+ 1 2) syntax. Fields are labelled $1, $2, $3, and so on.

Example:

(#(+ $1 $2) 1 2) ;; 3
(anon-fn-sugar (+ $1 $2)) ;; Fn

Note: This currently does not capture values.

;; >>> (def foo (fn (x) #(+ $1 x)))
;; nil
;; >>> ((foo 3) 5)
;; Error: Unknown Symbol x
;;
;; Stacktrace:
;; - Error in Fn, with args (5)

#+END_SRC

*** =bind=

#+BEGIN_SRC elisp
Bind symbol-value pairs, adding them to the symbol table.
Example:
(defn quicksort
"Sort a list."
(l)
(cond
(empty? l) l
true (bind
(pivot (head l)
rest (tail l)
le (filter (fn (x) (<= x pivot)) rest)
ge (filter (fn (x) (> x pivot)) rest))
(+ (quicksort le) (list pivot) (quicksort ge)))))

;; Bind also supports list patterns
(bind ((x y) '(1 2)) (+ x y)) ;; 3

#+END_SRC

*** =take=

#+BEGIN_SRC elisp
Take the first `n` items from a list or sequence.
Example:
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =find=

#+BEGIN_SRC elisp
Find and return some value matching a predicate in an iterator.

Note: This will stop iterating once it's found an item. If nothing is found, nil is returned.

Example:

>>> (find #(= $1 3) (take 4 (range)))
3
>>> (find #(= $1 300) (take 4 (range)))
nil

#+END_SRC

*** =slice=

#+BEGIN_SRC elisp
Slice a list.
Example:

>>> (def ll '(1 2 3 4 5 6))
nil
>>> (slice 0 2 ll)
(tuple 1 2)

#+END_SRC

*** =take-while=

#+BEGIN_SRC elisp
Continue taking items while `pred` is true.
Example:
(defn less-than-five (x) (< x 5))
(doall (take-while less-than-five (range))) ; (0 1 2 3 4)
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =doall=

#+BEGIN_SRC elisp
Evaluate a sequence, collecting the results into a list.
Example:
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =dict=

#+BEGIN_SRC elisp
Create a dict from the given elements.
Example:
(dict "a" 1 "b" 2) ;

#+END_SRC

*** =assoc=

#+BEGIN_SRC elisp
Create a new dict from an old dict with the given elements.
Example:
(assoc (dict) 1 2 3 4) ; {1: 2, 3: 4}

#+END_SRC

*** =remove=

#+BEGIN_SRC elisp
Remove a key-value pair from a dict.
Example:
(remove (dict 1 2) 1) ; {}

#+END_SRC

*** =set-dict=

#+BEGIN_SRC elisp
Set a key to a value in a dict. It'll return the new dict.
Example:
(set-dict (dict 1 2) 3 4) ; {1: 2, 3: 4}
(get (dict) 1 2) ; {1: 2}

#+END_SRC

*** =values=

#+BEGIN_SRC elisp
Get the values of a dict.
Example:
>>> (values (dict 1 2 3 4))
(tuple 2 4)
#+END_SRC

*** =get=

#+BEGIN_SRC elisp
Get a value from a dict by key.
Example:
(get (dict 1 2) 1) ; 2
(get (dict) 1) ; nil

#+END_SRC

*** =list=

#+BEGIN_SRC elisp
Create a list from the given elements.
Example:
(list 1 2 3) ; (1 2 3)

#+END_SRC

*** =tuple=

#+BEGIN_SRC elisp
Create a list from the given elements.
(tuple 1 2 3) ; (tuple 1 2 3)
;; It's usually easier to use the tuple syntax:
^(1 2 3) ; (tuple 1 2 3)

#+END_SRC

*** =nth=

#+BEGIN_SRC elisp
Extract the nth item from a list or tuple. Throws error if this fails.
Example
(nth 0 ^(1 2 3)) ; 1
(nth 1 '(1 2 3)) ; 2

#+END_SRC

*** =flatten=

#+BEGIN_SRC elisp
Flatten a list of lists.
Example:
>>> (flatten '('(1 2 3) '(4 5 6) 7))
(tuple 1 2 3 4 5 6 7)

#+END_SRC

*** =chars=

#+BEGIN_SRC elisp
Get a tuple of characters from a string.
Example:
(chars "hello") ;; (tuple "h" "e" "l" "l" "o")

#+END_SRC

*** =head=

#+BEGIN_SRC elisp
Get the first item in a list.
Example:
(head ()) ; nil
(head (1 2 3)) ; 1

#+END_SRC

*** =tail=

#+BEGIN_SRC elisp
Get all items after the first in a list or tuple.
(tail '(1 2 3)) ; (2 3)
(tail ^()) ; nil

#+END_SRC

*** =cons=

#+BEGIN_SRC elisp
Push an item to the front of a list.
Example:
(cons 1 '()) ; (1)
(cons 1 '(2 3)) ; (1 2 3)

#+END_SRC

*** =range=

#+BEGIN_SRC elisp
Generate a range of numbers. It accepts 0, 1, or 2 arguments. No arguments
yields an infinite range, one arg stops the range at that arg, and two args denote start..end.
Example:
(range) ; infinite range
(range 5) ; (0 1 2 3 4)
(range 5 10); (5 6 7 8 9)

#+END_SRC

*** =len=

#+BEGIN_SRC elisp
Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

#+END_SRC

*** =rev=

#+BEGIN_SRC elisp
Reverse a list.
#+END_SRC

*** =zip=

#+BEGIN_SRC elisp
Zip two lists together into a list of tuples.
#+END_SRC

*** =len=

#+BEGIN_SRC elisp
Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

#+END_SRC

*** =sort=

#+BEGIN_SRC elisp
Sort a given homogeneously typed list in ascending order. Returns an error if types are all not the same.
Example:
(sort '(3 7 0 5 4 8 1 2 6 9)) ; (0 1 2 3 4 5 6 7 8 9)

#+END_SRC

*** =distinct=

#+BEGIN_SRC elisp
Remove all duplicates from a list. This will sort the list.
Example:
(distinct '(1 1 1 2 2 0 0)) ; (0 1 2)

#+END_SRC

*** =inspect=

#+BEGIN_SRC elisp
Inspect values in a lazy iterator while its running.
Example:
>>> (doall (inspect #(println "curr_item=" $1) (take 3 (range))))
curr_item=0
curr_item=1
curr_item=2
(0 1 2)

#+END_SRC

*** =max-by=

#+BEGIN_SRC elisp
Get the maximum value of an iterator by a some function f. Throws an error if called with an empty iteratable.
Example:
(max-by
(fn (x) (nth 0 x))
(lazy (zip (range 10) (range 10)))) ;; (tuple 9 9)
#+END_SRC

*** =fs::open=

#+BEGIN_SRC elisp
Manipulate files in x9.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

#+END_SRC

*** =defrecord=

#+BEGIN_SRC elisp
Define a Record structure.

Use defmethod to add methods a record.

Example:
;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

;; Instantiate a Vec3
(def v (Vec 1 2 3))

;; Access attributes

v.x ;; 1
(.y v) ;; 2

#+END_SRC

*** =defmethod=

#+BEGIN_SRC elisp
Add a method to a record. Cannot be called on instantiated records.

NOTE: Methods get an implicit `self` reference.

;; Example

;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

(defmethod Vec3 +
"Add two vectors together"
(other)
(Vec3
(+ other.x self.x)
(+ other.y self.y)
(+ other.z self.z)))

(def v (Vec3 1 1 1))

(.+ v v) ;; (Vec3 2 2 2)
#+END_SRC

*** =call_method=

#+BEGIN_SRC elisp

Call a method on a record.

Example:

(def f (fs::open "Hello.txt"))
(call_method f "read_to_string") ;; no args required
(call_method f "write" "hello world") ;; pass it an arg

#+END_SRC

*** =re::compile=

#+BEGIN_SRC elisp
Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

#+END_SRC

*** =methods=

#+BEGIN_SRC elisp
Grab all documentation for a record's methods
#+END_SRC

*** =time=

#+BEGIN_SRC elisp
Return the time taken to evaluate an expression in milliseconds.
#+END_SRC

*** =catch-err=

#+BEGIN_SRC elisp
Catch an error. Returns nil if no error is caught.
#+END_SRC

*** =interner-stats=

#+BEGIN_SRC elisp
Internal string interner stats.
#+END_SRC

*** =print-smiley-face=

#+BEGIN_SRC elisp
print a smiley face
#+END_SRC

*** =assert-eq=

#+BEGIN_SRC elisp
Assert if two items are equal.
#+END_SRC

*** =TestResult=

#+BEGIN_SRC elisp
Result of a test
#+END_SRC

*** =not==

#+BEGIN_SRC elisp
Test if a sequence is not equal to each other.
Example:
(not= 1 1 2) ; false

#+END_SRC

*** =empty?=

#+BEGIN_SRC elisp
Test if a collection is empty.
#+END_SRC

*** =non-empty?=

#+BEGIN_SRC elisp
Test if a collection is non-empty.
#+END_SRC

*** =is-even?=

#+BEGIN_SRC elisp
Test if the given item is even.
#+END_SRC

*** =dot-product=

#+BEGIN_SRC elisp
Dot product two vectors.
Example:
(dot-product '(1 2 3) '(4 5 6)) ; 32

#+END_SRC

*** =quicksort=

#+BEGIN_SRC elisp
Sort a list using quicksort.
Example:
(quicksort '(3 1 2)) ; (1 2 3)

#+END_SRC

*** =fib=

#+BEGIN_SRC elisp
Find the `num'th Fibonacci number.
#+END_SRC

*** =docp=

#+BEGIN_SRC elisp
Pretty print the doc string of a function
Example: (docp docp) ;; Pretty print the doc string of a function...
#+END_SRC

*** =max=

#+BEGIN_SRC elisp
Maximum element in a list
#+END_SRC

*** =first=

#+BEGIN_SRC elisp
Get the first item of a collection, or nil. Same as head.
#+END_SRC

*** =second=

#+BEGIN_SRC elisp
Get the second item of a collection, or nil
#+END_SRC

*** =Set=

#+BEGIN_SRC elisp
Basic Hash Set in x9.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
(Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3))) ;; 4
(len (Set '())) ;; 0

#+END_SRC

*** =Set.contains=

#+BEGIN_SRC elisp
Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false
#+END_SRC

*** =Set.len=

#+BEGIN_SRC elisp
Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3)) ;; 4
(len (Set)) ;; 0
#+END_SRC

*** =Set.union=

#+BEGIN_SRC elisp
Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

#+END_SRC

*** =Set.intersection=

#+BEGIN_SRC elisp
Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>
#+END_SRC

*** =Set.to_list=

#+BEGIN_SRC elisp
Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

#+END_SRC

*** =Dict=

#+BEGIN_SRC elisp
Immutable dictionary.
Example:
(dict "a" 1 "b" 2) ;

#+END_SRC

*** =DictMut=

#+BEGIN_SRC elisp
Mutable dictionary type
#+END_SRC

*** =DictMut.Docs=

#+BEGIN_SRC elisp
TBD
#+END_SRC

*** =FileRecord=

#+BEGIN_SRC elisp
Manipulate files in x9.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

#+END_SRC

*** =FileRecord.read_to_string=

#+BEGIN_SRC elisp
Read a files as a string.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_to_string my-file) ; file contents

#+END_SRC

*** =FileRecord.read_lines=

#+BEGIN_SRC elisp
Get all lines of a file as a list.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_lines my-file) ; '("first_line" "second_line")

#+END_SRC

*** =FileRecord.write=

#+BEGIN_SRC elisp
Overwrite the file's content with the given string.
Example:
(def new-file (fs::open "new_file.txt"))
(.write "Hello world!")

#+END_SRC

*** =FileRecord.append_to_file=

#+BEGIN_SRC elisp
Append to a file without a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_to_file "Hello world!") ; file contains '...old-contents...Hello world!'

#+END_SRC

*** =FileRecord.append_line=

#+BEGIN_SRC elisp
Append a string to a file with a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_line "Hello world!") ; file contains '...old-contents...Hello world!
'

#+END_SRC

*** =Regex=

#+BEGIN_SRC elisp
Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

#+END_SRC

*** =Regex.is_match=

#+BEGIN_SRC elisp
Returns true if a string matches the regex.

Example:
(def re (re::compile "abc"))
(assert-eq true (.is_match re "abc") "Did not match!")
#+END_SRC

*** =Regex.captures=

#+BEGIN_SRC elisp
Returns a list of lists of all captures in the input.
;; Example
(def lines "15-16 f: ffffffffffffffhf
6-8 b: bbbnvbbb
6-10 z: zhzzzzfzzzzzzzzzpzz
9-13 s: dmssskssqsssssf")
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(.captures re lines)
;; Outputs:
((tuple "15" "16" "f" "ffffffffffffffhf")
(tuple "6" "8" "b" "bbbnvbbb")
(tuple "6" "10" "z" "zhzzzzfzzzzzzzzzpzz")
(tuple "9" "13" "s" "dmssskssqsssssf"))

#+END_SRC

*** =TcpListenerRecord=

#+BEGIN_SRC elisp
Tcp Socket Server TBD
#+END_SRC

*** =Set=

#+BEGIN_SRC elisp
Basic Hash Set in x9.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
(Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3))) ;; 4
(len (Set '())) ;; 0

#+END_SRC

*** =Set.contains=

#+BEGIN_SRC elisp
Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false
#+END_SRC

*** =Set.len=

#+BEGIN_SRC elisp
Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3)) ;; 4
(len (Set)) ;; 0
#+END_SRC

*** =Set.union=

#+BEGIN_SRC elisp
Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

#+END_SRC

*** =Set.intersection=

#+BEGIN_SRC elisp
Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>
#+END_SRC

*** =Set.to_list=

#+BEGIN_SRC elisp
Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

#+END_SRC

*** =WriteChan=

#+BEGIN_SRC elisp
Write side of a channel
#+END_SRC

*** =WriteChan.send=

#+BEGIN_SRC elisp
Sent some item into a channel.
;; `w` is some writer
(.send w "Some item 1")

#+END_SRC

*** =WriteChan.close=

#+BEGIN_SRC elisp
Close the writer. This will stop any readers on the channel.
#+END_SRC

*** =WriteChan.is_closed=

#+BEGIN_SRC elisp
Returns true if the channel is closed.
#+END_SRC

*** =ReadChan=

#+BEGIN_SRC elisp
Read side of a channel
#+END_SRC

*** =ReadChan.recv=

#+BEGIN_SRC elisp
Read some item from a channel. This will block until an item is received or the sender is closed. Example:

;; `w` is some writer
(bind
((writer reader) (chan))
(do
(go (fn () (do (println (.recv r))))) ;; recv items
(.send writer "item 1")
(sleep 1)
(.send writer "item 2")
(.close writer) ;; "item 1" and "item 2" are printed
))
#+END_SRC

*** =ReadChan.close=

#+BEGIN_SRC elisp
Close the reader. This will fail if the reader has been closed.
#+END_SRC

*** =ReadChan.is_closed=

#+BEGIN_SRC elisp
Returns true if the channel is closed.
#+END_SRC

*** =pretty-print=

#+BEGIN_SRC elisp
Format doc strings into something org-mode will agree with.
#+END_SRC

*** =+=

#+BEGIN_SRC elisp
Add two items together. Concatenates strings, lists, and tuples.
Example: (+ 1 1 1) ; 3
Example: (+ "Hello " "World") ; "Hello World"

#+END_SRC

*** =-=

#+BEGIN_SRC elisp
Subtracts all items from the first. Only works with Nums.
Example: (- 2 1 1) ; 0

#+END_SRC

*** =*=

#+BEGIN_SRC elisp
Multiply all items against the first. Works with Nums and (String Num*)
Example: (* 1 2 3) ; 6
(* "abc" 3) ; "abcabcabc"

#+END_SRC

*** =%=

#+BEGIN_SRC elisp
Take the remainder of the first item against the second.
Example: (% 4 2) ; 0
#+END_SRC

*** =/=

#+BEGIN_SRC elisp
Divide the first element by the rest.
Example: (/ 8 2 2 2) ; 1

#+END_SRC

*** =sqrt=

#+BEGIN_SRC elisp
Take the square root of a number. There's minor precision loss as it's way faster to convert to floats internally over using a bigdecimal.
Example: (sqrt 9) ; 3

#+END_SRC

*** ===

#+BEGIN_SRC elisp
Test if all items are equal.
Example: (= 1 1) ; true
(= 1) ; true

#+END_SRC

*** =<=

#+BEGIN_SRC elisp
Test if the first item is strictly smaller than the rest.
Example: (< 0 1 2) ; true
#+END_SRC

*** =<==

#+BEGIN_SRC elisp
Test if the first item is smaller or equal to the rest.
Example: (<= 0 0 0.05 1) ; true
#+END_SRC

*** =>=

#+BEGIN_SRC elisp
Test if the first item is strictly greater than the rest.
Example: (> 10 0 1 2 3 4) ; true
#+END_SRC

*** =>==

#+BEGIN_SRC elisp
Test if the first item is greater than or equal to the rest.
Example: (>= 10 10 5) ; true
#+END_SRC

*** =inc=

#+BEGIN_SRC elisp
Increment the given number.
Example:
(inc 2.2) ;; 3.3
(inc 1) ;; 2

#+END_SRC

*** =dec=

#+BEGIN_SRC elisp
Decrement the given number.
Example:
(dec 2.2) ;; 3.3
(dec 1) ;; 2

#+END_SRC

*** =pow=

#+BEGIN_SRC elisp
Raise a number to an exponent.
Example:
(pow 2 3) ;; 8
(pow 10 3) ;; 1000

#+END_SRC

*** =floor=

#+BEGIN_SRC elisp
Floor a number.
Example:
(floor 5.5) ;; 5.5

#+END_SRC

*** =int=

#+BEGIN_SRC elisp
Create an integer from the input.

Example:
(int 3.2) ;; 3

#+END_SRC

*** =not=

#+BEGIN_SRC elisp
Invert the bool. true becomes false and vice-versa.
#+END_SRC

*** =or=

#+BEGIN_SRC elisp
logical or.
#+END_SRC

*** =and=

#+BEGIN_SRC elisp
logical and.
#+END_SRC

*** =xor=

#+BEGIN_SRC elisp
logical xor.
#+END_SRC

*** =ident=

#+BEGIN_SRC elisp
Identity function. Returns what you give it.
#+END_SRC

*** =quote=

#+BEGIN_SRC elisp
Transforms the given input into a quote. Usually you will want to use the '(1 2 3) syntax.
#+END_SRC

*** =symbol=

#+BEGIN_SRC elisp
Turn a string into a symbol
#+END_SRC

*** =str=

#+BEGIN_SRC elisp
Make a string
#+END_SRC

*** =bool=

#+BEGIN_SRC elisp
Coerce a value to bool. In general if a collection is non-empty, it is true. The len method is called on Records
#+END_SRC

*** =print=

#+BEGIN_SRC elisp
Print the given argument WITHOUT a newline.
#+END_SRC

*** =println=

#+BEGIN_SRC elisp
Print the given argument WITH a newline.
#+END_SRC

*** =split=

#+BEGIN_SRC elisp
Split a string with some substring.
Example:
>>> (split "," "hello, world")
(tuple "hello" " world")

#+END_SRC

*** =replace=

#+BEGIN_SRC elisp
Replace a substring in a string with some other string.
Example:
>>> (replace "abc" "OwO" "abc def")
"OwO def"
#+END_SRC

*** =ident-exists=

#+BEGIN_SRC elisp
Returns true if a given symbol exists in the interpeter
#+END_SRC

*** =eval=

#+BEGIN_SRC elisp
Eval an expression.
Example (in repl):
>>> '(+ 1 2)
(+ 1 2)
>>> (eval '(+ 1 2))
3
#+END_SRC

*** =parse=

#+BEGIN_SRC elisp
Parse an expression.
Example (in repl):
>>> (parse "(+ 1 2)")
#+END_SRC

*** =def=

#+BEGIN_SRC elisp
Associate a given symbol with a value. Overwrites local variables.
Example:
>>> (def a 3)
>>> a
3

#+END_SRC

*** =cond=

#+BEGIN_SRC elisp
Branching control flow construct. Given an even list of [pred then], if `pred` is true, return `then`.
Example:
(def input 10)
(cond
(= input 3) (print "input is 3")
(= input 10) (print "input is 10")
true (print "hit base case, input is: " input))

#+END_SRC

*** =match=

#+BEGIN_SRC elisp
Branching control flow construct. Given an item and an even list of [value then], if `item` == `value`, return `then`.
Example:
(def input 10)
(match input
3 (print "input is 3")
10 (print "input is 10")
_ (print "hit base case, input is: " input))

#+END_SRC

*** =if=

#+BEGIN_SRC elisp
Branching control flow construct. Given pred?, then, and else, if pred? is true, return then, otherwise, else.
Note: Does not evaluate branches not taken.
Example:
(def input 10)
(if (= input 10)
(print "input is 10!")
(print ":[ input is not 10"))

#+END_SRC

*** =shuffle=

#+BEGIN_SRC elisp
Shuffle (randomize) a given list.
Example:
>>> (shuffle (range 10))
(6 3 2 9 4 0 1 8 5 7)

#+END_SRC

*** =go=

#+BEGIN_SRC elisp
Run a function in a new thread. Example:
(go (fn ()
(do
(sleep 2)
(println "from another thread!"))))

;; After two seconds, something is printed
#+END_SRC

*** =chan=

#+BEGIN_SRC elisp
Make a channel. Returns a tuple of (writer, reader). Example:
(bind
((w r) (chan))
(do
(go (fn () (print-recv r)))
(.send w "in bind context 1")
(sleep 1)
(.send w "in bind context 2")
(.close w)
))

;; Two things are printed.
#+END_SRC

*** =random_bool=

#+BEGIN_SRC elisp
Randomly return true or false.
#+END_SRC

*** =random_int=

#+BEGIN_SRC elisp
Randomly return an integer between lower and upper.

Example:
(random_int 0 10) ;; Returns a num between 0 and 10 (exclusive)
#+END_SRC

*** =panic=

#+BEGIN_SRC elisp
Abort the program printing the given message.

Example: (panic "goodbye") ; kills program

Your console will print the following:

thread 'main' panicked at 'goodbye', src/stdlib.rs:216:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

... and the interpreter will stop.

#+END_SRC

*** =primes=

#+BEGIN_SRC elisp
Prime numbers less than `n`.
#+END_SRC

*** =divisors=

#+BEGIN_SRC elisp
Divisors of `n`. Example:
(divisors 20) ;; ^(1 2 4 5 10 20)
#+END_SRC

*** =sleep=

#+BEGIN_SRC elisp
Sleep for n seconds.
Example: (sleep 10) ; sleep for 10 seconds.
#+END_SRC

*** =type=

#+BEGIN_SRC elisp
Return the type of the argument as a string.
Example: (type "hello") ; str
#+END_SRC

*** =doc=

#+BEGIN_SRC elisp
Return the documentation of a symbol as a string.
Example: (doc doc) ; Return the documentation of a symbol as a...
#+END_SRC

*** =err=

#+BEGIN_SRC elisp
Return an error with a message string.
Example: (err "Something bad happened!") ; return an error
#+END_SRC

*** =all-symbols=

#+BEGIN_SRC elisp
Return all symbols defined in the interpreter.
#+END_SRC

*** =include=

#+BEGIN_SRC elisp
Include a file into the interpreter.
#+END_SRC

*** =map=

#+BEGIN_SRC elisp
Apply a function to each element of a sequence and return a list.
Example: (map inc '(1 2 3)) ; (2 3 4)

#+END_SRC

*** =inline_transform=

#+BEGIN_SRC elisp
Given a list of data and another of functions, apply each function pairwise onto the list.
Example:

(defn adder-maker (x) (fn (y) (+ x y)))

(inline_transform
'(1 1 1)
(list (adder-maker 1) (adder-maker 2) (adder-maker 3))) ;; ^(2 3 4)

#+END_SRC

*** =foreach=

#+BEGIN_SRC elisp
Eagerly apply the given function to a sequence or list.
Example:
(foreach
(fn (x) (println x))
(range 20)) ; prints 0 to 20. Returns ().

(foreach
(fn (x) (println x))
(take 5 (map (fn (x) (* x x x x x x)) (range)))) ; prints 0, 1, 64, 729, 4096

#+END_SRC

*** =filter=

#+BEGIN_SRC elisp
Retain elements in a sequence according to a predicate.
Example:
(defn is-odd (x) (= 1 (% x 2)))
(filter is-odd (range 20)) ; outputs (1 3 5 7 9 11 13 15 17 19)

#+END_SRC

*** =any=

#+BEGIN_SRC elisp
Ask whether a predicate is true in some sequence. Short circuits.
#+END_SRC

*** =all=

#+BEGIN_SRC elisp
Ask whether a predicate is true for every element of a sequence. Short circuits.
#+END_SRC

*** =lazy=

#+BEGIN_SRC elisp
Turn a list into a lazy sequence. Useful for building complex iterators over some source list.
#+END_SRC

*** =skip=

#+BEGIN_SRC elisp
Skip some amount in a lazy iterator.
#+END_SRC

*** =product=

#+BEGIN_SRC elisp
Cartesian Product every list passed in.
Example:
>>> (doall (product '(0 1) '(0 1) '(0 1)))
(
(tuple 0 0 0)
(tuple 1 0 0)
(tuple 0 1 0)
(tuple 1 1 0)
(tuple 0 0 1)
(tuple 1 0 1)
(tuple 0 1 1)
(tuple 1 1 1)
)

#+END_SRC

*** =apply=

#+BEGIN_SRC elisp
Apply a function to a given list.
(def my-list '(1 2 3))
(apply + my-list) ; outputs 6

#+END_SRC

*** =do=

#+BEGIN_SRC elisp
Evaluate a sequence of expressions and return the last one.
Example:
(defn complex-fn (x)
(do
(print "current state: " x)
(+ x x)))

#+END_SRC

*** =partial=

#+BEGIN_SRC elisp
;; Construct a partial function.

;; Example:
(defn foobar (x y z) (+ x y z))

(def part (partial foobar 1 2))
(part 3) ;; 6

((partial foobar 1) 0 -1) ;; 0

(partial + 1) ;; Fn; remaining=0>, 0, [ ]>

#+END_SRC

*** =comp=

#+BEGIN_SRC elisp
Compose given functions and return a new function. NOT IMPLEMENTED YET!
#+END_SRC

*** =reduce=

#+BEGIN_SRC elisp
Reduce (fold) a given sequence using the given function. Reduce is multi-arity, and will accept an `init` parameter.
Example:
(reduce + '(1 2 3)) ; 6
(reduce + 100 '(1 2 3)) ; 106

#+END_SRC

*** =fn=

#+BEGIN_SRC elisp
Create a anonymous function.
Example:
(fn (x) (* x 2)) ; Fn

#+END_SRC

*** =defn=

#+BEGIN_SRC elisp
Define a function and add it to the symbol table. Supports doc strings.
Example:
(defn is-odd? (x) (= 1 (% x 2)))
(defn get-odd-numbers
"Extract the odd numbers out of the given sequence `x`"
(x)
(filter is-odd? x)) ; for fun, try (doc get-odd-numbers)

#+END_SRC

*** =anon-fn-sugar=

#+BEGIN_SRC elisp
Create an anonymous, automatic binding function. You normally want to use the #(+ 1 2) syntax. Fields are labelled $1, $2, $3, and so on.

Example:

(#(+ $1 $2) 1 2) ;; 3
(anon-fn-sugar (+ $1 $2)) ;; Fn

Note: This currently does not capture values.

;; >>> (def foo (fn (x) #(+ $1 x)))
;; nil
;; >>> ((foo 3) 5)
;; Error: Unknown Symbol x
;;
;; Stacktrace:
;; - Error in Fn, with args (5)

#+END_SRC

*** =bind=

#+BEGIN_SRC elisp
Bind symbol-value pairs, adding them to the symbol table.
Example:
(defn quicksort
"Sort a list."
(l)
(cond
(empty? l) l
true (bind
(pivot (head l)
rest (tail l)
le (filter (fn (x) (<= x pivot)) rest)
ge (filter (fn (x) (> x pivot)) rest))
(+ (quicksort le) (list pivot) (quicksort ge)))))

;; Bind also supports list patterns
(bind ((x y) '(1 2)) (+ x y)) ;; 3

#+END_SRC

*** =take=

#+BEGIN_SRC elisp
Take the first `n` items from a list or sequence.
Example:
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =find=

#+BEGIN_SRC elisp
Find and return some value matching a predicate in an iterator.

Note: This will stop iterating once it's found an item. If nothing is found, nil is returned.

Example:

>>> (find #(= $1 3) (take 4 (range)))
3
>>> (find #(= $1 300) (take 4 (range)))
nil

#+END_SRC

*** =slice=

#+BEGIN_SRC elisp
Slice a list.
Example:

>>> (def ll '(1 2 3 4 5 6))
nil
>>> (slice 0 2 ll)
(tuple 1 2)

#+END_SRC

*** =take-while=

#+BEGIN_SRC elisp
Continue taking items while `pred` is true.
Example:
(defn less-than-five (x) (< x 5))
(doall (take-while less-than-five (range))) ; (0 1 2 3 4)
(take 2 '(1 2 3)) ; (1 2)
(take 5 (range)) ; lazy seq of (0 1 2 3 4)
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =doall=

#+BEGIN_SRC elisp
Evaluate a sequence, collecting the results into a list.
Example:
(doall (take 5 (range))) ; (0 1 2 3 4)

#+END_SRC

*** =dict=

#+BEGIN_SRC elisp
Create a dict from the given elements.
Example:
(dict "a" 1 "b" 2) ;

#+END_SRC

*** =assoc=

#+BEGIN_SRC elisp
Create a new dict from an old dict with the given elements.
Example:
(assoc (dict) 1 2 3 4) ; {1: 2, 3: 4}

#+END_SRC

*** =remove=

#+BEGIN_SRC elisp
Remove a key-value pair from a dict.
Example:
(remove (dict 1 2) 1) ; {}

#+END_SRC

*** =set-dict=

#+BEGIN_SRC elisp
Set a key to a value in a dict. It'll return the new dict.
Example:
(set-dict (dict 1 2) 3 4) ; {1: 2, 3: 4}
(get (dict) 1 2) ; {1: 2}

#+END_SRC

*** =values=

#+BEGIN_SRC elisp
Get the values of a dict.
Example:
>>> (values (dict 1 2 3 4))
(tuple 2 4)
#+END_SRC

*** =get=

#+BEGIN_SRC elisp
Get a value from a dict by key.
Example:
(get (dict 1 2) 1) ; 2
(get (dict) 1) ; nil

#+END_SRC

*** =list=

#+BEGIN_SRC elisp
Create a list from the given elements.
Example:
(list 1 2 3) ; (1 2 3)

#+END_SRC

*** =tuple=

#+BEGIN_SRC elisp
Create a list from the given elements.
(tuple 1 2 3) ; (tuple 1 2 3)
;; It's usually easier to use the tuple syntax:
^(1 2 3) ; (tuple 1 2 3)

#+END_SRC

*** =nth=

#+BEGIN_SRC elisp
Extract the nth item from a list or tuple. Throws error if this fails.
Example
(nth 0 ^(1 2 3)) ; 1
(nth 1 '(1 2 3)) ; 2

#+END_SRC

*** =flatten=

#+BEGIN_SRC elisp
Flatten a list of lists.
Example:
>>> (flatten '('(1 2 3) '(4 5 6) 7))
(tuple 1 2 3 4 5 6 7)

#+END_SRC

*** =chars=

#+BEGIN_SRC elisp
Get a tuple of characters from a string.
Example:
(chars "hello") ;; (tuple "h" "e" "l" "l" "o")

#+END_SRC

*** =head=

#+BEGIN_SRC elisp
Get the first item in a list.
Example:
(head ()) ; nil
(head (1 2 3)) ; 1

#+END_SRC

*** =tail=

#+BEGIN_SRC elisp
Get all items after the first in a list or tuple.
(tail '(1 2 3)) ; (2 3)
(tail ^()) ; nil

#+END_SRC

*** =cons=

#+BEGIN_SRC elisp
Push an item to the front of a list.
Example:
(cons 1 '()) ; (1)
(cons 1 '(2 3)) ; (1 2 3)

#+END_SRC

*** =range=

#+BEGIN_SRC elisp
Generate a range of numbers. It accepts 0, 1, or 2 arguments. No arguments
yields an infinite range, one arg stops the range at that arg, and two args denote start..end.
Example:
(range) ; infinite range
(range 5) ; (0 1 2 3 4)
(range 5 10); (5 6 7 8 9)

#+END_SRC

*** =len=

#+BEGIN_SRC elisp
Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

#+END_SRC

*** =rev=

#+BEGIN_SRC elisp
Reverse a list.
#+END_SRC

*** =zip=

#+BEGIN_SRC elisp
Zip two lists together into a list of tuples.
#+END_SRC

*** =len=

#+BEGIN_SRC elisp
Get the number of items in a list or tuple.
Example:
(len '(0 0 0)) ; 3
(len '()) ; 0

#+END_SRC

*** =sort=

#+BEGIN_SRC elisp
Sort a given homogeneously typed list in ascending order. Returns an error if types are all not the same.
Example:
(sort '(3 7 0 5 4 8 1 2 6 9)) ; (0 1 2 3 4 5 6 7 8 9)

#+END_SRC

*** =distinct=

#+BEGIN_SRC elisp
Remove all duplicates from a list. This will sort the list.
Example:
(distinct '(1 1 1 2 2 0 0)) ; (0 1 2)

#+END_SRC

*** =max-by=

#+BEGIN_SRC elisp
Get the maximum value of an iterator by a some function f. Throws an error if called with an empty iteratable.
Example:
(max-by
(fn (x) (nth 0 x))
(lazy (zip (range 10) (range 10)))) ;; (tuple 9 9)
#+END_SRC

*** =fs::open=

#+BEGIN_SRC elisp
Manipulate files in x9.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

#+END_SRC

*** =defrecord=

#+BEGIN_SRC elisp
Define a Record structure.

Use defmethod to add methods a record.

Example:
;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

;; Instantiate a Vec3
(def v (Vec 1 2 3))

;; Access attributes

v.x ;; 1
(.y v) ;; 2

#+END_SRC

*** =defmethod=

#+BEGIN_SRC elisp
Add a method to a record. Cannot be called on instantiated records.

NOTE: Methods get an implicit `self` reference.

;; Example

;; Define a record
(defrecord Vec3 "Three Dimensional Vector" x y z)

(defmethod Vec3 +
"Add two vectors together"
(other)
(Vec3
(+ other.x self.x)
(+ other.y self.y)
(+ other.z self.z)))

(def v (Vec3 1 1 1))

(.+ v v) ;; (Vec3 2 2 2)
#+END_SRC

*** =call_method=

#+BEGIN_SRC elisp

Call a method on a record.

Example:

(def f (fs::open "Hello.txt"))
(call_method f "read_to_string") ;; no args required
(call_method f "write" "hello world") ;; pass it an arg

#+END_SRC

*** =re::compile=

#+BEGIN_SRC elisp
Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

#+END_SRC

*** =methods=

#+BEGIN_SRC elisp
Grab all documentation for a record's methods
#+END_SRC

*** =time=

#+BEGIN_SRC elisp
Return the time taken to evaluate an expression in milliseconds.
#+END_SRC

*** =catch-err=

#+BEGIN_SRC elisp
Catch an error. Returns nil if no error is caught.
#+END_SRC

*** =interner-stats=

#+BEGIN_SRC elisp
Internal string interner stats.
#+END_SRC

*** =assert-eq=

#+BEGIN_SRC elisp
Assert if two items are equal.
#+END_SRC

*** =TestResult=

#+BEGIN_SRC elisp
Result of a test
#+END_SRC

*** =not==

#+BEGIN_SRC elisp
Test if a sequence is not equal to each other.
Example:
(not= 1 1 2) ; false

#+END_SRC

*** =empty?=

#+BEGIN_SRC elisp
Test if a collection is empty.
#+END_SRC

*** =non-empty?=

#+BEGIN_SRC elisp
Test if a collection is non-empty.
#+END_SRC

*** =is-even?=

#+BEGIN_SRC elisp
Test if the given item is even.
#+END_SRC

*** =dot-product=

#+BEGIN_SRC elisp
Dot product two vectors.
Example:
(dot-product '(1 2 3) '(4 5 6)) ; 32

#+END_SRC

*** =quicksort=

#+BEGIN_SRC elisp
Sort a list using quicksort.
Example:
(quicksort '(3 1 2)) ; (1 2 3)

#+END_SRC

*** =fib=

#+BEGIN_SRC elisp
Find the `num'th Fibonacci number.
#+END_SRC

*** =docp=

#+BEGIN_SRC elisp
Pretty print the doc string of a function
Example: (docp docp) ;; Pretty print the doc string of a function...
#+END_SRC

*** =max=

#+BEGIN_SRC elisp
Maximum element in a list
#+END_SRC

*** =Set=

#+BEGIN_SRC elisp
Basic Hash Set in x9.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
(Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3))) ;; 4
(len (Set '())) ;; 0

#+END_SRC

*** =Set.contains=

#+BEGIN_SRC elisp
Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false
#+END_SRC

*** =Set.len=

#+BEGIN_SRC elisp
Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3)) ;; 4
(len (Set)) ;; 0
#+END_SRC

*** =Set.union=

#+BEGIN_SRC elisp
Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

#+END_SRC

*** =Set.intersection=

#+BEGIN_SRC elisp
Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>
#+END_SRC

*** =Set.to_list=

#+BEGIN_SRC elisp
Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

#+END_SRC

*** =Dict=

#+BEGIN_SRC elisp
Immutable dictionary.
Example:
(dict "a" 1 "b" 2) ;

#+END_SRC

*** =DictMut=

#+BEGIN_SRC elisp
Mutable dictionary type
#+END_SRC

*** =DictMut.Docs=

#+BEGIN_SRC elisp
TBD
#+END_SRC

*** =FileRecord=

#+BEGIN_SRC elisp
Manipulate files in x9.
Example:
(def my-file (fs::open "my_file.txt"))

;; Write to the file
(.write my-file "Hello World")

;; Read from the file
(.read_to_string my-file)

#+END_SRC

*** =FileRecord.read_to_string=

#+BEGIN_SRC elisp
Read a files as a string.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_to_string my-file) ; file contents

#+END_SRC

*** =FileRecord.read_lines=

#+BEGIN_SRC elisp
Get all lines of a file as a list.
Example:
(def my-file (fs::open "my_file.txt"))
(.read_lines my-file) ; '("first_line" "second_line")

#+END_SRC

*** =FileRecord.write=

#+BEGIN_SRC elisp
Overwrite the file's content with the given string.
Example:
(def new-file (fs::open "new_file.txt"))
(.write "Hello world!")

#+END_SRC

*** =FileRecord.append_to_file=

#+BEGIN_SRC elisp
Append to a file without a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_to_file "Hello world!") ; file contains '...old-contents...Hello world!'

#+END_SRC

*** =FileRecord.append_line=

#+BEGIN_SRC elisp
Append a string to a file with a newline.
Example:
(def new-file (fs::open "new_file.txt"))
(.append_line "Hello world!") ; file contains '...old-contents...Hello world!
'

#+END_SRC

*** =Regex=

#+BEGIN_SRC elisp
Regular Expressions - regular search patterns.

This is backed by the excellent regex crate: https://github.com/rust-lang/regex

Example:

;; Compile a regex
(def a (re::compile "(abc)+"))

;; Test if a string matches

(.is_match a "abcabc") ;; true
(.is_match a "ab") ;; false

#+END_SRC

*** =Regex.is_match=

#+BEGIN_SRC elisp
Returns true if a string matches the regex.

Example:
(def re (re::compile "abc"))
(assert-eq true (.is_match re "abc") "Did not match!")
#+END_SRC

*** =Regex.captures=

#+BEGIN_SRC elisp
Returns a list of lists of all captures in the input.
;; Example
(def lines "15-16 f: ffffffffffffffhf
6-8 b: bbbnvbbb
6-10 z: zhzzzzfzzzzzzzzzpzz
9-13 s: dmssskssqsssssf")
(def re (re::compile "(\d+)-(\d+) (.): (.*)"))
(.captures re lines)
;; Outputs:
((tuple "15" "16" "f" "ffffffffffffffhf")
(tuple "6" "8" "b" "bbbnvbbb")
(tuple "6" "10" "z" "zhzzzzfzzzzzzzzzpzz")
(tuple "9" "13" "s" "dmssskssqsssssf"))

#+END_SRC

*** =Set=

#+BEGIN_SRC elisp
Basic Hash Set in x9.

;; Contains. Test whether an element exists in a Set. O(1) time.
;; Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false

;; Union (creates new Set with elements from each)
;; Example:
(.union (Set 1 2 3)
(Set 4 5 6)) ;; Set<{4, 5, 2, 6, 1, 3}>
(.union (apply Set (range 5)) (apply Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

;; Intersection. Obtain the intersection of two Sets.
;; Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>

;; to_list. Convert the Set into a list. Order is undefined.
;; Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

;; len. Get the number of elements in a Set. Implements the "len" magic method.
;; Example:
(.len (Set '(0 1 2 3))) ;; 4
(len (Set '())) ;; 0

#+END_SRC

*** =Set.contains=

#+BEGIN_SRC elisp
Test whether an element exists in a set. O(1) time.
Example:
(.contains (Set 0 1 2 3) 2) ;; true
(.contains (Set 0 1 2 3) 10) ;; false
#+END_SRC

*** =Set.len=

#+BEGIN_SRC elisp
Get the number of elements in a Set. Implements the "len" magic method.
Example:
(.len (Set 0 1 2 3)) ;; 4
(len (Set)) ;; 0
#+END_SRC

*** =Set.union=

#+BEGIN_SRC elisp
Obtain the union of two Sets.
Example:
(.union (Set (range 5)) (Set (range 5 10)))
;; Set<{5, 1, 7, 4, 3, 2, 8, 0, 9, 6}>

#+END_SRC

*** =Set.intersection=

#+BEGIN_SRC elisp
Obtain the intersection of two Sets.
Example:
(.intersection (apply Set (range 10)) (apply Set (range 5 10)))
;; Set<{5, 6, 9, 7, 8}>
#+END_SRC

*** =Set.to_list=

#+BEGIN_SRC elisp
Convert the Set into a list. Order is undefined.
Example:
(.to_list (apply Set (range 5))) ;; (1 2 0 3 4)

#+END_SRC

*** =WriteChan=
#+BEGIN_SRC elisp
Write side of a channel
#+END_SRC

*** =WriteChan.send=

#+BEGIN_SRC elisp
Sent some item into a channel.
;; `w` is some writer
(.send w "Some item 1")

#+END_SRC

*** =WriteChan.close=

#+BEGIN_SRC elisp
Close the writer. This will stop any readers on the channel.
#+END_SRC

*** =WriteChan.is_closed=

#+BEGIN_SRC elisp
Returns true if the channel is closed.
#+END_SRC

*** =ReadChan.close=

#+BEGIN_SRC elisp
Close the reader. This will fail if the reader has been closed.
#+END_SRC

*** =ReadChan.is_closed=

#+BEGIN_SRC elisp
Returns true if the channel is closed.
#+END_SRC

*** =pretty-print=

#+BEGIN_SRC elisp
Format doc strings into something org-mode will agree with.
#+END_SRC

* Thanks
A big thanks to the [[https://github.com/Geal/nom][nom]] people (Geal et all) for having an s_expression example for my parser!