summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/cljlib.md (renamed from doc/core.md)615
-rw-r--r--doc/macros.md559
2 files changed, 566 insertions, 608 deletions
diff --git a/doc/core.md b/doc/cljlib.md
index 578efef..b1678f5 100644
--- a/doc/core.md
+++ b/doc/cljlib.md
@@ -1,10 +1,8 @@
-# Core (v1.1.1)
-Fennel-cljlib - functions from Clojure's core.clj implemented on top
-of Fennel.
+# Cljlib (v1.1.1)
+Fennel-cljlib - functions from Clojure's core.clj implemented on top of Fennel.
-This library contains a set of functions providing functions that
-behave similarly to Clojure's equivalents. Library itself has nothing
-Fennel specific, so it should work on Lua, e.g:
+This library contains a set of functions providing functions that behave similarly to Clojure's equivalents.
+The library itself apart from macros has nothing Fennel-specific, so it should work on Lua, e.g.:
``` lua
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
@@ -13,41 +11,45 @@ Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
-- 1 4 9
```
-This example is mapping an anonymous `function` over a table,
-producing new table and concatenating it with `" "`.
+This example is mapping an anonymous `function` over a table, producing a new table, and concatenating it with `" "`.
-However, this library also provides Fennel-specific set of
-[macros](./macros.md), that provides additional facilities like `defn`
-or `defmulti` which extend the language allowing writing code that
-looks and works mostly like Clojure.
+However, this library also provides a Fennel-specific set of [macros](./macros.md), which provides additional facilities like [`defn`](#defn) or [`defmulti`](#defmulti) which extends the language allowing writing code that looks and works mostly like Clojure.
-Each function in this library is created with `defn`, which is a
-special macro for creating multi-arity functions. So when you see
-function signature like `(foo [x])`, this means that this is function
-`foo`, that accepts exactly one argument `x`. In contrary, functions
-created with `fn` will produce `(foo x)` signature (`x` is not inside
-brackets).
+Each function in this library is created with [`defn`](#defn), which is a special macro for creating multi-arity functions.
+So when you see a function signature like `(foo [x])`, this means that this is function `foo`, which accepts exactly one argument `x`.
+On the contrary, functions created with `fn` will produce a `(foo x)` signature (`x` is not inside brackets).
-Functions, which signatures look like `(foo ([x]) ([x y]) ([x y &
-zs]))`, it is a multi-arity function, which accepts either one, two,
-or three-or-more arguments. Each `([...])` represents different body
-of a function which is chosen by checking amount of arguments passed
-to the function. See [Clojure's doc section on multi-arity
-functions](https://clojure.org/guides/learn/functions#_multi_arity_functions).
+Functions, which signatures look like `(foo ([x]) ([x y]) ([x y & zs]))`, it is a multi-arity function, which accepts either one, two, or three or more arguments.
+Each `([...])` represents a different body of a function which is chosen by checking the amount of arguments passed to the function.
+See [Clojure's doc section on multi-arity functions](https://clojure.org/guides/learn/functions#_multi_arity_functions).
## Compatibility
-This library is mainly developed with Lua 5.4, and tested against
-Lua 5.2, 5.3, 5.4, and LuaJIT 2.1.0-beta3. Note, that in lua 5.2 and
-LuaJIT equality semantics are a bit different from Lua 5.3 and Lua 5.4.
-Main difference is that when comparing two tables, they must have
-exactly the same `__eq` metamethods, so comparing hash sets with hash
-sets will work, but comparing sets with other tables works only in
-Lua5.3+. Another difference is that Lua 5.2 and LuaJIT don't have
-inbuilt UTF-8 library, therefore [`seq`](#seq) function will not work for
-non-ASCII strings.
+
+This library is mainly developed with Lua 5.4 and tested against Lua 5.2, 5.3, 5.4, and LuaJIT 2.1.0-beta3.
+Note, that in Lua 5.2 and LuaJIT equality semantics are a bit different from Lua 5.3 and Lua 5.4.
+The main difference is that when comparing two tables, they must have exactly the same `__eq` metamethods, so comparing hash sets with hash sets will work, but comparing sets with other tables works only in Lua5.3+.
+Another difference is that Lua 5.2 and LuaJIT don't have an inbuilt UTF-8 library, therefore [`seq`](#seq) function will not work for non-ASCII strings.
**Table of contents**
+- [`ns`](#ns)
+- [`in-ns`](#in-ns)
+- [`def`](#def)
+- [`fn*`](#fn)
+- [`defn`](#defn)
+- [`defn-`](#defn-)
+- [`time`](#time)
+- [`if-let`](#if-let)
+- [`when-let`](#when-let)
+- [`if-some`](#if-some)
+- [`when-some`](#when-some)
+- [`defmulti`](#defmulti)
+- [`defmethod`](#defmethod)
+- [`cond`](#cond)
+- [`loop`](#loop)
+- [`try`](#try)
+- [`lazy-seq`](#lazy-seq)
+- [`lazy-cat`](#lazy-cat)
- [`apply`](#apply)
- [`add`](#add)
- [`sub`](#sub)
@@ -152,7 +154,6 @@ non-ASCII strings.
- [`iterate`](#iterate)
- [`keep`](#keep)
- [`keep-indexed`](#keep-indexed)
-- [`lazy-seq`](#lazy-seq)
- [`line-seq`](#line-seq)
- [`list`](#list)
- [`list*`](#list-1)
@@ -195,6 +196,532 @@ non-ASCII strings.
- [`vec`](#vec)
- [`zipmap`](#zipmap)
+## `ns`
+Function signature:
+
+```
+(ns name commentary requirements)
+```
+
+Namespace declaration macro.
+Accepts the `name` of the generated namespace, and creates a local
+variable with this name holding a table. Optionally accepts
+`commentary` describing what namespace is about and a `requirements`
+spec, specifying what libraries should be required.
+
+The `requirements` spec is a list that consists of vectors, specifying
+library name and a possible alias or a vector of names to refer to
+without a prefix:
+
+``` fennel
+(ns some-namespace
+ "Description of the some-namespace."
+ (:require [some.lib]
+ [some.other.lib :as lib2]
+ [another.lib :refer [foo bar baz]]))
+
+(defn inc [x] (+ x 1))
+```
+
+Which is equivalent to:
+
+``` fennel
+(local some-namespace {})
+(local lib (require :some.lib))
+(local lib2 (require :some.other.lib))
+(local {:bar bar :baz baz :foo foo} (require :another.lib))
+(comment "Description of the some-namespace.")
+```
+
+Note that when no `:as` alias is given, the library will be named
+after the innermost part of the require path, i.e. `some.lib` is
+transformed to `lib`.
+
+See `in-ns` on how to switch namespaces.
+
+## `in-ns`
+Function signature:
+
+```
+(in-ns name)
+```
+
+Sets the compile-time variable `cljlib-namespaces` to the given `name`.
+Affects such macros as `def`, `defn`, which will bind names to the
+specified namespace.
+
+### Examples
+Creating several namespaces in the file, and defining functions in each:
+
+``` fennel
+(ns a)
+(defn f [] "f from a")
+(ns b)
+(defn f [] "f from b")
+(in-ns a)
+(defn g [] "g from a")
+(in-ns b)
+(defn g [] "g from b")
+
+(assert-eq (a.f) "f from a")
+(assert-eq (b.f) "f from b")
+(assert-eq (a.g) "g from a")
+(assert-eq (b.g) "g from b")
+```
+
+Note, switching namespaces in the REPL doesn't affect non-namespaced
+local bindings. In other words, when defining a local with `def`, a
+bot a local binding and a namespaced binding are created, and
+switching current namespace won't change the local binding:
+
+``` fennel
+>> (ns foo)
+nil
+>> (def x 42)
+nil
+>> (ns bar)
+nil
+>> (def x 1337)
+nil
+>> (in-ns foo)
+#<namespace: foo>
+>> x ; user might have expected to see 42 here
+1337
+>> foo.x
+42
+>> bar.x
+1337
+```
+
+Sadly, Fennel itself has no support for namespace switching in REPL,
+so this feature can be only partially emulated by the cljlib library.
+
+
+## `def`
+Function signature:
+
+```
+(def ([name initializer]) ([meta name initializer]))
+```
+
+Name binding macro similar to `local` but acts in terms of current
+namespace set with the `ns` macro, unless `:private` was passed before
+the binding name. Accepts the `name` to be bound and the `initializer`
+expression. `meta` can be either an associative table where keys are
+strings, or a string representing a key from the table. If a sole
+string is given, its value is set to `true` in the meta table.
+
+## `fn*`
+Function signature:
+
+```
+(fn* ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
+```
+
+Clojure-inspired `fn` macro for defining functions.
+Accepts an optional `name` and `docstring?`, followed by the binding
+list containing function's `params*`. The `body` is wrapped in an
+implicit `do`. The `doc-string?` argument specifies an optional
+documentation for the function. Supports multi-arity dispatching via
+the following syntax:
+
+(fn* optional-name
+ optional-docstring
+ ([arity1] body1)
+ ([other arity2] body2))
+
+Accepts `pre-post?` conditions in a form of a table after argument
+list:
+
+(fn* optional-name
+ optional-docstring
+ [arg1 arg2]
+ {:pre [(check1 arg1 arg2) (check2 arg1)]
+ :post [(check1 $) ... (checkN $)]}
+ body)
+
+The same syntax applies to multi-arity version.
+
+(pre- and post-checks are not yet implemented)
+
+## `defn`
+Function signature:
+
+```
+(defn ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
+```
+
+Same as `(def name (fn* name docstring? [params*] pre-post? exprs*))`
+or `(def name (fn* name docstring? ([params*] pre-post? exprs*)+))`
+with any doc-string or attrs added to the function metadata. Accepts
+`name` which will be used to refer to a function in the current
+namespace, and optional `doc-string?`, a vector of function's
+`params*`, `pre-post?` conditions, and the `body` of the function.
+The body is wrapped in an implicit do. See `fn*` for more info.
+
+## `defn-`
+Function signature:
+
+```
+(defn- ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
+```
+
+Same as `(def :private name (fn* name docstring? [params*] pre-post?
+exprs*))` or `(def :private name (fn* name docstring? ([params*]
+pre-post? exprs*)+))` with any doc-string or attrs added to the
+function metadata. Accepts `name` which will be used to refer to a
+function, and optional `doc-string?`, a vector of function's
+`params*`, `pre-post?` conditions, and the `body` of the function.
+The body is wrapped in an implicit do. See `fn*` for more info.
+
+## `time`
+Function signature:
+
+```
+(time expr)
+```
+
+Measure the CPU time spent executing `expr`.
+
+## `if-let`
+Function signature:
+
+```
+(if-let [name test] if-branch else-branch)
+```
+
+When `test` is logical `true`, evaluates the `if-branch` with `name`
+bound to the value of `test`. Otherwise, evaluates the `else-branch`
+
+## `when-let`
+Function signature:
+
+```
+(when-let [name test] & body)
+```
+
+When `test` is logical `true`, evaluates the `body` with `name` bound
+to the value of `test`.
+
+## `if-some`
+Function signature:
+
+```
+(if-some [name test] if-branch else-branch)
+```
+
+When `test` is not `nil`, evaluates the `if-branch` with `name`
+bound to the value of `test`. Otherwise, evaluates the `else-branch`
+
+## `when-some`
+Function signature:
+
+```
+(when-some [name test] & body)
+```
+
+When `test` is not `nil`, evaluates the `body` with `name` bound to
+the value of `test`.
+
+## `defmulti`
+Function signature:
+
+```
+(defmulti name docstring? dispatch-fn options*)
+```
+
+Create multifunction `name` with runtime dispatching based on results
+from `dispatch-fn`. Returns a proxy table with `__call` metamethod,
+that calls `dispatch-fn` on its arguments. Amount of arguments
+passed, should be the same as accepted by `dispatch-fn`. Looks for
+multimethod based on result from `dispatch-fn`.
+
+Accepts optional `docstring?`, and `options*` arguments, where
+`options*` is a sequence of key value pairs representing additional
+attributes. Supported options:
+
+`:default` - the default dispatch value, defaults to `:default`.
+
+By default, multifunction has no multimethods, see
+[`defmethod`](#defmethod) on how to add one.
+
+## `defmethod`
+Function signature:
+
+```
+(defmethod multi-fn dispatch-value fnspec)
+```
+
+Attach new method to multi-function dispatch value. Accepts the
+`multi-fn` as its first argument, the `dispatch-value` as second, and
+`fnspec` - a function tail starting from argument list, followed by
+function body as in [`fn*`](#fn).
+
+### Examples
+Here are some examples how multimethods can be used.
+
+#### Factorial example
+Key idea here is that multimethods can call itself with different
+values, and will dispatch correctly. Here, `fac` recursively calls
+itself with less and less number until it reaches `0` and dispatches
+to another multimethod:
+
+``` fennel
+(ns test)
+
+(defmulti fac (fn [x] x))
+
+(defmethod fac 0 [_] 1)
+(defmethod fac :default [x] (* x (fac (- x 1))))
+
+(assert-eq (fac 4) 24)
+```
+
+`:default` is a special method which gets called when no other methods
+were found for given dispatch value.
+
+#### Multi-arity dispatching
+Multi-arity function tails are also supported:
+
+``` fennel
+(ns test)
+
+(defmulti foo (fn* ([x] [x]) ([x y] [x y])))
+
+(defmethod foo [10] [_] (print "I knew I'll get 10"))
+(defmethod foo [10 20] [_ _] (print "I knew I'll get both 10 and 20"))
+(defmethod foo :default ([x] (print (.. "Umm, got" x)))
+ ([x y] (print (.. "Umm, got both " x " and " y))))
+```
+
+Calling `(foo 10)` will print `"I knew I'll get 10"`, and calling
+`(foo 10 20)` will print `"I knew I'll get both 10 and 20"`.
+However, calling `foo` with any other numbers will default either to
+`"Umm, got x"` message, when called with single value, and `"Umm, got
+both x and y"` when calling with two values.
+
+#### Dispatching on object's type
+We can dispatch based on types the same way we dispatch on values.
+For example, here's a naive conversion from Fennel's notation for
+tables to Lua's one:
+
+``` fennel
+(ns test)
+
+(defmulti to-lua-str (fn [x] (type x)))
+
+(defmethod to-lua-str :number [x] (tostring x))
+(defmethod to-lua-str :table [x]
+ (let [res []]
+ (each [k v (pairs x)]
+ (table.insert res (.. "[" (to-lua-str k) "] = " (to-lua-str v))))
+ (.. "{" (table.concat res ", ") "}")))
+(defmethod to-lua-str :string [x] (.. "\"" x "\""))
+(defmethod to-lua-str :default [x] (tostring x))
+
+(assert-eq (to-lua-str {:a {:b 10}}) "{[\"a\"] = {[\"b\"] = 10}}")
+
+(assert-eq (to-lua-str [:a :b :c [:d {:e :f}]])
+ "{[1] = \"a\", [2] = \"b\", [3] = \"c\", [4] = {[1] = \"d\", [2] = {[\"e\"] = \"f\"}}}")
+```
+
+And if we call it on some table, we'll get a valid Lua table, which we
+can then reformat as we want and use in Lua.
+
+All of this can be done with functions, and single entry point
+function, that uses if statement and branches on the type, however one
+of the additional features of multimethods, is that separate libraries
+can extend such multimethod by adding additional claues to it without
+needing to patch the source of the function. For example later on
+support for userdata or coroutines can be added to `to-lua-str`
+function as a separate multimethods for respective types.
+
+## `cond`
+Function signature:
+
+```
+(cond ...)
+```
+
+Takes a set of test expression pairs. It evaluates each test one at a
+time. If a test returns logical true, `cond` evaluates and returns
+the value of the corresponding expression and doesn't evaluate any of
+the other tests or exprs. `(cond)` returns nil.
+
+## `loop`
+Function signature:
+
+```
+(loop binding-vec body*)
+```
+
+Recursive loop macro.
+
+Similar to `let`, but binds a special `recur` call that will reassign
+the values of the `binding-vec` and restart the loop `body*`. Unlike
+`let`, doesn't support multiple-value destructuring.
+
+The first argument is a binding table with alternating symbols (or destructure
+forms), and the values to bind to them.
+
+For example:
+
+``` fennel
+(loop [[first & rest] [1 2 3 4 5]
+ i 0]
+ (if (= nil first)
+ i
+ (recur rest (+ 1 i))))
+```
+
+This would destructure the first table argument, with the first value inside it
+being assigned to `first` and the remainder of the table being assigned to
+`rest`. `i` simply gets bound to 0.
+
+The body of the form executes for every item in the table, calling `recur` each
+time with the table lacking its head element (thus consuming one element per
+iteration), and with `i` being called with one value greater than the previous.
+
+When the loop terminates (When the user doesn't call `recur`) it will return the
+number of elements in the passed in table. (In this case, 5)
+
+### Limitations
+
+In order to only evaluate expressions once and support sequential
+bindings, the binding table has to be transformed like this:
+
+``` fennel
+(loop [[x & xs] (foo)
+ y (+ x 1)]
+ ...)
+
+(let [_1_ (foo)
+ [x & xs] _1_
+ _2_ (+ x 1)
+ y _2_]
+ ((fn recur [[x & xs] y] ...) _1_ _2_)
+```
+
+This ensures that `foo` is called only once, its result is cached in a
+`sym1#` binding, and that `y` can use the destructured value, obtained
+from that binding. The value of this binding is later passed to the
+function to begin the first iteration.
+
+This has two unfortunate consequences. One is that the initial
+destructuring happens twice - first, to make sure that later bindings
+can be properly initialized, and second, when the first looping
+function call happens. Another one is that as a result, `loop` macro
+can't work with multiple-value destructuring, because these can't be
+cached as described above. E.g. this will not work:
+
+``` fennel
+(loop [(x y) (foo)] ...)
+```
+
+Because it would be transformed to:
+
+``` fennel
+(let [_1_ (foo)
+ (x y) _1_]
+ ((fn recur [(x y)] ...) _1_)
+```
+
+`x` is correctly set, but `y` is completely lost. Therefore, this
+macro checks for lists in bindings.
+
+## `try`
+Function signature:
+
+```
+(try body* catch-clause* finally-clause?)
+```
+
+General purpose try/catch/finally macro.
+Wraps its body in `pcall` and checks the return value with `match`
+macro.
+
+Catch clause is written either as `(catch symbol body*)`, thus acting
+as catch-all, or `(catch value body*)` for catching specific errors.
+It is possible to have several `catch` clauses. If no `catch` clauses
+specified, an implicit catch-all clause is created. `body*`, and
+inner expressions of `catch-clause*`, and `finally-clause?` are
+wrapped in implicit `do`.
+
+The `finally` clause is optional, and written as (finally body*). If
+present, it must be the last clause in the [`try`](#try) form, and the only
+`finally` clause. Note that `finally` clause is for side effects
+only, and runs either after succesful run of [`try`](#try) body, or after any
+`catch` clause body, before returning the result. If no `catch`
+clause is provided `finally` runs in implicit catch-all clause, and
+trows error to upper scope using `error` function.
+
+To throw error from [`try`](#try) to catch it with `catch` clause use `error`
+or `assert` functions.
+
+### Examples
+Catch all errors, ignore those and return fallback value:
+
+``` fennel
+(fn add [x y]
+ (try
+ (+ x y)
+ (catch _ 0)))
+
+(assert-eq (add nil 1) 0)
+```
+
+Catch error and do cleanup:
+
+``` fennel
+(local tbl [])
+
+(try
+ (table.insert tbl "a")
+ (table.insert tbl "b" "c")
+ (catch _
+ (each [k _ (pairs tbl)]
+ (tset tbl k nil))))
+
+(assert-eq (length tbl) 0)
+
+```
+
+Always run some side effect action:
+
+``` fennel
+(local t [])
+(local res (try 10 (finally (table.insert t :finally))))
+(assert-eq (. t 1) :finally)
+(assert-eq res 10)
+
+(local res (try (error 10) (catch 10 nil) (finally (table.insert t :again))))
+(assert-eq (. t 2) :again)
+(assert-eq res nil)
+```
+
+## `lazy-seq`
+Function signature:
+
+```
+(lazy-seq & body)
+```
+
+Takes a `body` of expressions that returns a sequence, table or nil,
+and yields a lazy sequence that will invoke the body only the first
+time `seq` is called, and will cache the result and return it on all
+subsequent `seq` calls. See also - `realized?`
+
+## `lazy-cat`
+Function signature:
+
+```
+(lazy-cat & colls)
+```
+
+Expands to code which yields a lazy sequence of the concatenation of
+`colls` - expressions returning collections. Each expression is not
+evaluated until it is needed.
+
## `apply`
Function signature:
@@ -406,7 +933,7 @@ Function signature:
Test if `mf` is an instance of `multifn`.
-`multifn` is a special kind of table, created with `defmulti` macros
+`multifn` is a special kind of table, created with [`defmulti`](#defmulti) macros
from `macros.fnl`.
## `set?`
@@ -930,6 +1457,7 @@ Returns the nth rest of `coll`, `coll` when `n` is 0.
(assert-eq (nthrest [1 2 3 4] 0) [1 2 3 4])
```
+
## `partition`
Function signature:
@@ -1524,17 +2052,6 @@ the `coll`. Note, this means false return values will be included.
`f` must be free of side effects. Returns a transducer when no
collection is provided.
-## `lazy-seq`
-Function signature:
-
-```
-(lazy-seq [f])
-```
-
-Create lazy sequence from the result of calling a function `f`.
-Delays execution of `f` until sequence is consumed. `f` must return a
-sequence or a vector.
-
## `line-seq`
Function signature:
@@ -1556,7 +2073,7 @@ Bear in mind, that since the sequence is lazy it should be realized or
truncated before the file is closed:
``` fennel
-(let [lines (with-open [f (io.open "init.fnl" :r)]
+(let [lines (with-open [f (io.open "cljlib.fnl" :r)]
(line-seq f))]
;; this will error because only first line was realized, but the
;; file was closed before the rest of lines were cached
@@ -1566,7 +2083,7 @@ truncated before the file is closed:
Sequence is realized with `doall` before file was closed and can be shared:
``` fennel
-(let [lines (with-open [f (io.open "init.fnl" :r)]
+(let [lines (with-open [f (io.open "cljlib.fnl" :r)]
(doall (line-seq f)))]
(assert-is (pcall next lines)))
```
@@ -2095,5 +2612,5 @@ Copyright (C) 2020-2021 Andrey Listopadov
License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE)
-<!-- Generated with Fenneldoc v0.1.9
+<!-- Generated with Fenneldoc v1.0.1
https://gitlab.com/andreyorst/fenneldoc -->
diff --git a/doc/macros.md b/doc/macros.md
deleted file mode 100644
index 9c20e56..0000000
--- a/doc/macros.md
+++ /dev/null
@@ -1,559 +0,0 @@
-# Macros (v1.1.1)
-Macros for fennel-cljlib.
-
-**Table of contents**
-
-- [`cond`](#cond)
-- [`def`](#def)
-- [`defmethod`](#defmethod)
-- [`defmulti`](#defmulti)
-- [`defn`](#defn)
-- [`defn-`](#defn-)
-- [`fn*`](#fn)
-- [`if-let`](#if-let)
-- [`if-some`](#if-some)
-- [`in-ns`](#in-ns)
-- [`lazy-cat`](#lazy-cat)
-- [`lazy-seq`](#lazy-seq)
-- [`loop`](#loop)
-- [`ns`](#ns)
-- [`time`](#time)
-- [`try`](#try)
-- [`when-let`](#when-let)
-- [`when-some`](#when-some)
-
-## `cond`
-Function signature:
-
-```
-(cond ...)
-```
-
-Takes a set of test expression pairs. It evaluates each test one at a
-time. If a test returns logical true, `cond` evaluates and returns
-the value of the corresponding expression and doesn't evaluate any of
-the other tests or exprs. `(cond)` returns nil.
-
-## `def`
-Function signature:
-
-```
-(def ([name initializer]) ([meta name initializer]))
-```
-
-Name binding macro similar to `local` but acts in terms of current
-namespace set with the `ns` macro, unless `:private` was passed before
-the binding name. Accepts the `name` to be bound and the `initializer`
-expression. `meta` can be either an associative table where keys are
-strings, or a string representing a key from the table. If a sole
-string is given, its value is set to `true` in the meta table.
-
-## `defmethod`
-Function signature:
-
-```
-(defmethod multi-fn dispatch-value fnspec)
-```
-
-Attach new method to multi-function dispatch value. Accepts the
-`multi-fn` as its first argument, the `dispatch-value` as second, and
-`fnspec` - a function tail starting from argument list, followed by
-function body as in [`fn*`](#fn).
-
-### Examples
-Here are some examples how multimethods can be used.
-
-#### Factorial example
-Key idea here is that multimethods can call itself with different
-values, and will dispatch correctly. Here, `fac` recursively calls
-itself with less and less number until it reaches `0` and dispatches
-to another multimethod:
-
-``` fennel
-(ns test)
-
-(defmulti fac (fn [x] x))
-
-(defmethod fac 0 [_] 1)
-(defmethod fac :default [x] (* x (fac (- x 1))))
-
-(assert-eq (fac 4) 24)
-```
-
-`:default` is a special method which gets called when no other methods
-were found for given dispatch value.
-
-#### Multi-arity dispatching
-Multi-arity function tails are also supported:
-
-``` fennel
-(ns test)
-
-(defmulti foo (fn* ([x] [x]) ([x y] [x y])))
-
-(defmethod foo [10] [_] (print "I knew I'll get 10"))
-(defmethod foo [10 20] [_ _] (print "I knew I'll get both 10 and 20"))
-(defmethod foo :default ([x] (print (.. "Umm, got" x)))
- ([x y] (print (.. "Umm, got both " x " and " y))))
-```
-
-Calling `(foo 10)` will print `"I knew I'll get 10"`, and calling
-`(foo 10 20)` will print `"I knew I'll get both 10 and 20"`.
-However, calling `foo` with any other numbers will default either to
-`"Umm, got x"` message, when called with single value, and `"Umm, got
-both x and y"` when calling with two values.
-
-#### Dispatching on object's type
-We can dispatch based on types the same way we dispatch on values.
-For example, here's a naive conversion from Fennel's notation for
-tables to Lua's one:
-
-``` fennel
-(ns test)
-
-(defmulti to-lua-str (fn [x] (type x)))
-
-(defmethod to-lua-str :number [x] (tostring x))
-(defmethod to-lua-str :table [x]
- (let [res []]
- (each [k v (pairs x)]
- (table.insert res (.. "[" (to-lua-str k) "] = " (to-lua-str v))))
- (.. "{" (table.concat res ", ") "}")))
-(defmethod to-lua-str :string [x] (.. "\"" x "\""))
-(defmethod to-lua-str :default [x] (tostring x))
-
-(assert-eq (to-lua-str {:a {:b 10}}) "{[\"a\"] = {[\"b\"] = 10}}")
-
-(assert-eq (to-lua-str [:a :b :c [:d {:e :f}]])
- "{[1] = \"a\", [2] = \"b\", [3] = \"c\", [4] = {[1] = \"d\", [2] = {[\"e\"] = \"f\"}}}")
-```
-
-And if we call it on some table, we'll get a valid Lua table, which we
-can then reformat as we want and use in Lua.
-
-All of this can be done with functions, and single entry point
-function, that uses if statement and branches on the type, however one
-of the additional features of multimethods, is that separate libraries
-can extend such multimethod by adding additional claues to it without
-needing to patch the source of the function. For example later on
-support for userdata or coroutines can be added to `to-lua-str`
-function as a separate multimethods for respective types.
-
-## `defmulti`
-Function signature:
-
-```
-(defmulti name docstring? dispatch-fn options*)
-```
-
-Create multifunction `name` with runtime dispatching based on results
-from `dispatch-fn`. Returns a proxy table with `__call` metamethod,
-that calls `dispatch-fn` on its arguments. Amount of arguments
-passed, should be the same as accepted by `dispatch-fn`. Looks for
-multimethod based on result from `dispatch-fn`.
-
-Accepts optional `docstring?`, and `options*` arguments, where
-`options*` is a sequence of key value pairs representing additional
-attributes. Supported options:
-
-`:default` - the default dispatch value, defaults to `:default`.
-
-By default, multifunction has no multimethods, see
-[`defmethod`](#defmethod) on how to add one.
-
-## `defn`
-Function signature:
-
-```
-(defn ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
-```
-
-Same as `(def name (fn* name docstring? [params*] pre-post? exprs*))`
-or `(def name (fn* name docstring? ([params*] pre-post? exprs*)+))`
-with any doc-string or attrs added to the function metadata. Accepts
-`name` which will be used to refer to a function in the current
-namespace, and optional `doc-string?`, a vector of function's
-`params*`, `pre-post?` conditions, and the `body` of the function.
-The body is wrapped in an implicit do. See `fn*` for more info.
-
-## `defn-`
-Function signature:
-
-```
-(defn- ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
-```
-
-Same as `(def :private name (fn* name docstring? [params*] pre-post?
-exprs*))` or `(def :private name (fn* name docstring? ([params*]
-pre-post? exprs*)+))` with any doc-string or attrs added to the
-function metadata. Accepts `name` which will be used to refer to a
-function, and optional `doc-string?`, a vector of function's
-`params*`, `pre-post?` conditions, and the `body` of the function.
-The body is wrapped in an implicit do. See `fn*` for more info.
-
-## `fn*`
-Function signature:
-
-```
-(fn* ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +]))
-```
-
-Clojure-inspired `fn` macro for defining functions.
-Accepts an optional `name` and `docstring?`, followed by the binding
-list containing function's `params*`. The `body` is wrapped in an
-implicit `do`. The `doc-string?` argument specifies an optional
-documentation for the function. Supports multi-arity dispatching via
-the following syntax:
-
-(fn* optional-name
- optional-docstring
- ([arity1] body1)
- ([other arity2] body2))
-
-Accepts `pre-post?` conditions in a form of a table after argument
-list:
-
-(fn* optional-name
- optional-docstring
- [arg1 arg2]
- {:pre [(check1 arg1 arg2) (check2 arg1)]
- :post [(check1 $) ... (checkN $)]}
- body)
-
-The same syntax applies to multi-arity version.
-
-(pre- and post-checks are not yet implemented)
-
-## `if-let`
-Function signature:
-
-```
-(if-let [name test] if-branch else-branch)
-```
-
-When `test` is logical `true`, evaluates the `if-branch` with `name`
-bound to the value of `test`. Otherwise, evaluates the `else-branch`
-
-## `if-some`
-Function signature:
-
-```
-(if-some [name test] if-branch else-branch)
-```
-
-When `test` is not `nil`, evaluates the `if-branch` with `name`
-bound to the value of `test`. Otherwise, evaluates the `else-branch`
-
-## `in-ns`
-Function signature:
-
-```
-(in-ns name)
-```
-
-Sets the compile-time variable `cljlib-namespaces` to the given `name`.
-Affects such macros as `def`, `defn`, which will bind names to the
-specified namespace.
-
-### Examples
-Creating several namespaces in the file, and defining functions in each:
-
-``` fennel
-(ns a)
-(defn f [] "f from a")
-(ns b)
-(defn f [] "f from b")
-(in-ns a)
-(defn g [] "g from a")
-(in-ns b)
-(defn g [] "g from b")
-
-(assert-eq (a.f) "f from a")
-(assert-eq (b.f) "f from b")
-(assert-eq (a.g) "g from a")
-(assert-eq (b.g) "g from b")
-```
-
-Note, switching namespaces in the REPL doesn't affect non-namespaced
-local bindings. In other words, when defining a local with `def`, a
-bot a local binding and a namespaced binding are created, and
-switching current namespace won't change the local binding:
-
-``` fennel
->> (ns foo)
-nil
->> (def x 42)
-nil
->> (ns bar)
-nil
->> (def x 1337)
-nil
->> (in-ns foo)
-#<namespace: foo>
->> x ; user might have expected to see 42 here
-1337
->> foo.x
-42
->> bar.x
-1337
-```
-
-Sadly, Fennel itself has no support for namespace switching in REPL,
-so this feature can be only partially emulated by the cljlib library.
-
-## `lazy-cat`
-Function signature:
-
-```
-(lazy-cat & colls)
-```
-
-Expands to code which yields a lazy sequence of the concatenation of
-`colls` - expressions returning collections. Each expression is not
-evaluated until it is needed.
-
-## `lazy-seq`
-Function signature:
-
-```
-(lazy-seq & body)
-```
-
-Takes a `body` of expressions that returns a sequence, table or nil,
-and yields a lazy sequence that will invoke the body only the first
-time `seq` is called, and will cache the result and return it on all
-subsequent `seq` calls. See also - `realized?`
-
-## `loop`
-Function signature:
-
-```
-(loop binding-vec body*)
-```
-
-Recursive loop macro.
-
-Similar to `let`, but binds a special `recur` call that will reassign
-the values of the `binding-vec` and restart the loop `body*`. Unlike
-`let`, doesn't support multiple-value destructuring.
-
-The first argument is a binding table with alternating symbols (or destructure
-forms), and the values to bind to them.
-
-For example:
-
-``` fennel
-(loop [[first & rest] [1 2 3 4 5]
- i 0]
- (if (= nil first)
- i
- (recur rest (+ 1 i))))
-```
-
-This would destructure the first table argument, with the first value inside it
-being assigned to `first` and the remainder of the table being assigned to
-`rest`. `i` simply gets bound to 0.
-
-The body of the form executes for every item in the table, calling `recur` each
-time with the table lacking its head element (thus consuming one element per
-iteration), and with `i` being called with one value greater than the previous.
-
-When the loop terminates (When the user doesn't call `recur`) it will return the
-number of elements in the passed in table. (In this case, 5)
-
-### Limitations
-
-In order to only evaluate expressions once and support sequential
-bindings, the binding table has to be transformed like this:
-
-``` fennel
-(loop [[x & xs] (foo)
- y (+ x 1)]
- ...)
-
-(let [_1_ (foo)
- [x & xs] _1_
- _2_ (+ x 1)
- y _2_]
- ((fn recur [[x & xs] y] ...) _1_ _2_)
-```
-
-This ensures that `foo` is called only once, its result is cached in a
-`sym1#` binding, and that `y` can use the destructured value, obtained
-from that binding. The value of this binding is later passed to the
-function to begin the first iteration.
-
-This has two unfortunate consequences. One is that the initial
-destructuring happens twice - first, to make sure that later bindings
-can be properly initialized, and second, when the first looping
-function call happens. Another one is that as a result, `loop` macro
-can't work with multiple-value destructuring, because these can't be
-cached as described above. E.g. this will not work:
-
-``` fennel
-(loop [(x y) (foo)] ...)
-```
-
-Because it would be transformed to:
-
-``` fennel
-(let [_1_ (foo)
- (x y) _1_]
- ((fn recur [(x y)] ...) _1_)
-```
-
-`x` is correctly set, but `y` is completely lost. Therefore, this
-macro checks for lists in bindings.
-
-## `ns`
-Function signature:
-
-```
-(ns name commentary requirements)
-```
-
-Namespace declaration macro.
-Accepts the `name` of the generated namespace, and creates a local
-variable with this name holding a table. Optionally accepts
-`commentary` describing what namespace is about and a `requirements`
-spec, specifying what libraries should be required.
-
-The `requirements` spec is a list that consists of vectors, specifying
-library name and a possible alias or a vector of names to refer to
-without a prefix:
-
-``` fennel
-(ns some-namespace
- "Description of the some-namespace."
- (:require [some.lib]
- [some.other.lib :as lib2]
- [another.lib :refer [foo bar baz]]))
-
-(defn inc [x] (+ x 1))
-```
-
-Which is equivalent to:
-
-``` fennel
-(local some-namespace {})
-(local lib (require :some.lib))
-(local lib2 (require :some.other.lib))
-(local {:bar bar :baz baz :foo foo} (require :another.lib))
-(comment "Description of the some-namespace.")
-```
-
-Note that when no `:as` alias is given, the library will be named
-after the innermost part of the require path, i.e. `some.lib` is
-transformed to `lib`.
-
-See `in-ns` on how to switch namespaces.
-
-## `time`
-Function signature:
-
-```
-(time expr)
-```
-
-Measure the CPU time spent executing `expr`.
-
-## `try`
-Function signature:
-
-```
-(try body* catch-clause* finally-clause?)
-```
-
-General purpose try/catch/finally macro.
-Wraps its body in `pcall` and checks the return value with `match`
-macro.
-
-Catch clause is written either as `(catch symbol body*)`, thus acting
-as catch-all, or `(catch value body*)` for catching specific errors.
-It is possible to have several `catch` clauses. If no `catch` clauses
-specified, an implicit catch-all clause is created. `body*`, and
-inner expressions of `catch-clause*`, and `finally-clause?` are
-wrapped in implicit `do`.
-
-The `finally` clause is optional, and written as (finally body*). If
-present, it must be the last clause in the [`try`](#try) form, and the only
-`finally` clause. Note that `finally` clause is for side effects
-only, and runs either after succesful run of [`try`](#try) body, or after any
-`catch` clause body, before returning the result. If no `catch`
-clause is provided `finally` runs in implicit catch-all clause, and
-trows error to upper scope using `error` function.
-
-To throw error from [`try`](#try) to catch it with `catch` clause use `error`
-or `assert` functions.
-
-### Examples
-Catch all errors, ignore those and return fallback value:
-
-``` fennel
-(fn add [x y]
- (try
- (+ x y)
- (catch _ 0)))
-
-(assert-eq (add nil 1) 0)
-```
-
-Catch error and do cleanup:
-
-``` fennel
-(local tbl [])
-
-(try
- (table.insert tbl "a")
- (table.insert tbl "b" "c")
- (catch _
- (each [k _ (pairs tbl)]
- (tset tbl k nil))))
-
-(assert-eq (length tbl) 0)
-
-```
-
-Always run some side effect action:
-
-``` fennel
-(local t [])
-(local res (try 10 (finally (table.insert t :finally))))
-(assert-eq (. t 1) :finally)
-(assert-eq res 10)
-
-(local res (try (error 10) (catch 10 nil) (finally (table.insert t :again))))
-(assert-eq (. t 2) :again)
-(assert-eq res nil)
-```
-
-## `when-let`
-Function signature:
-
-```
-(when-let [name test] & body)
-```
-
-When `test` is logical `true`, evaluates the `body` with `name` bound
-to the value of `test`.
-
-## `when-some`
-Function signature:
-
-```
-(when-some [name test] & body)
-```
-
-When `test` is not `nil`, evaluates the `body` with `name` bound to
-the value of `test`.
-
-
----
-
-Copyright (C) 2020-2021 Andrey Listopadov
-
-License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE)
-
-
-<!-- Generated with Fenneldoc v0.1.9
- https://gitlab.com/andreyorst/fenneldoc -->