x7
x7 copied to clipboard
Speedy self-documenting lisp in Rust.
#+AUTHOR: David Briggs
- The x7 Programming Language
x7 is a lisp I built to better understand programming languages and interpreters.
The standard library is being written in either x7 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<bottom, 1, [ x ]>, with args ("a")
- Error in Fn<middle, 1, [ x ]>, with args ("a")
- Error in Fn<top, 0, [ ]>, with args () #+end_src #+end_example
*** Convenient FFI
x7 offers easy and convenient embedding into other rust programs.
#+begin_src rust use x7::ffi::{X7Interpreter, ForeignData};
let interpreter = X7Interpreter::new();
let res = interpreter.run_program::
You can interface your own types in x7 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 x7's Expr type.
#+begin_src rust
let interpreter = X7Interpreter::new();
let my_sum_fn = |args: Vec
// And verify we get u64 with value 6 out of it.
assert_eq!(interpreter.run_program::
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
The reason it works is we embed the type information into the function added to the interpreter, and x7'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.x7 ;; Run with: x7 fib.x7
;; 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 =x7= 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<Vec3, fields=[ x: 2 y: 2 z: 2 ]> #+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, uninitialized> (Point 0 0) Record<Point, fields=[ x: 0 y: 0 ]> #+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<Point, fields=[ x: 0 y: 0 ]> 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<curried_method_call<Vec3
; #args=1>, 0, [ ]> (v.scale 3) Record<Vec3, fields=[ x: 3 y: 3 z: 3 ]> 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
x7 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<Expr>), Function(Arc<Function>), Nil, String(String), Quote(Vector<Expr>), Tuple(Vector<Expr>), Bool(bool), LazyIter(IterType), Dict(Dict), Record(crate::records::RecordType), } #+end_src
*** =Num=
Numbers in x7 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 =x7=. See the [[https://github.com/dpbriggs/x7#dynamic-records-and-syntactic-sugar][record section above]].
** Standard Library Reference
The x7 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.x7 #+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<Partial<Fn<+, 1, [ ]>; 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<AnonFn, 1, [ x ]>
#+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<AnonFn, 0, [ ]>
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<AnonFn, 0, [ ]>, 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 x7. 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 x7.
;; 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 x7. 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 x7.
;; 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<Partial<Fn<+, 1, [ ]>; 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<AnonFn, 1, [ x ]>
#+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<AnonFn, 0, [ ]>
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<AnonFn, 0, [ ]>, 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 x7. 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 x7.
;; 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 x7. 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 x7.
;; 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
- 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!