diff options
| author | Andrey Listopadov <andreyorst@gmail.com> | 2022-08-21 21:25:30 +0300 |
|---|---|---|
| committer | Andrey Listopadov <andreyorst@gmail.com> | 2022-08-21 21:25:30 +0300 |
| commit | 3f738c3368ddaadbaa4372443cece90651d1ccd2 (patch) | |
| tree | 4ebcceeecdd01e8375b7b7f0a7172b2fe2620f09 | |
| parent | 9bbe5ddf93c7c8b17a73318bc89dd1330f4f3f59 (diff) | |
update docs, readme and cnagelog for v1.0.0 release
| -rw-r--r-- | .fenneldoc | 114 | ||||
| -rw-r--r-- | CHANGELOG.md | 29 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | doc/cljlib.md | 1263 | ||||
| -rw-r--r-- | doc/core.md | 2078 | ||||
| -rw-r--r-- | doc/macros.md | 609 |
7 files changed, 2398 insertions, 1703 deletions
@@ -1,5 +1,5 @@ ;; -*- mode: fennel; -*- vi:ft=fennel -;; Configuration file for Fenneldoc v0.1.6 +;; Configuration file for Fenneldoc v0.1.9 ;; https://gitlab.com/andreyorst/fenneldoc {:fennel-path {} @@ -14,6 +14,11 @@ "more" "keys" "tbl" + "_" + "cs" + "sep" + "coll" + "Set" "s[0-9]+" "ss" "args"] @@ -22,11 +27,16 @@ :insert-copyright true :insert-license true :insert-version true + :keys {:copyright "_COPYRIGHT" + :description "_DESCRIPTION" + :doc-order "_DOC_ORDER" + :license "_LICENSE" + :module-name "_MODULE_NAME" + :version "_VERSION"} :mode "checkdoc" - :order "alphabetic" - :out-dir "./doc" - :modules-info {:init.fnl {:name "core" - :description "Fennel-cljlib - functions from Clojure's core.clj implemented on top + :modules-info {:init-macros.fnl {:description "Macros for fennel-cljlib." + :name "macros"} + :init.fnl {:description "Fennel-cljlib - functions from Clojure's core.clj implemented on top of Fennel. This library contains a set of functions providing functions that @@ -72,24 +82,86 @@ 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' function will not work for non-ASCII strings." - :doc-order [:apply :add :sub :mul :div :le :lt :ge :gt :inc :dec :eq - :map? :vector? :multifn? :set? :nil? :zero? :pos? - :neg? :even? :odd? :string? :boolean? :true? :false? - :int? :pos-int? :neg-int? :double? :empty? :not-empty - :map? :vector? :multifn? :set? :nil? :zero? :pos? - :neg? :even? :odd? :string? :boolean? :true? :false? - :int? :pos-int? :neg-int? :double? :empty? :not-empty - :vector :seq :kvseq :first :rest :last :butlast - :conj :disj :cons :concat :reduce :reduced :reduce-kv - :mapv :filter :every? :some :not-any? :range :reverse :take - :nthrest :partition - :identity :comp :complement :constantly :memoize - :assoc :hash-map :get :get-in :keys :vals :find :dissoc - :remove-method :remove-all-methods :methods :get-method - :ordered-set :hash-set]}} + :doc-order ["apply" + "add" + "sub" + "mul" + "div" + "le" + "lt" + "ge" + "gt" + "inc" + "dec" + "eq" + "map?" + "vector?" + "multifn?" + "set?" + "nil?" + "zero?" + "pos?" + "neg?" + "even?" + "odd?" + "string?" + "boolean?" + "true?" + "false?" + "int?" + "pos-int?" + "neg-int?" + "double?" + "empty?" + "not-empty" + "vector" + "seq" + "first" + "rest" + "last" + "butlast" + "conj" + "disj" + "cons" + "concat" + "reduce" + "reduced" + "reduce-kv" + "mapv" + "filter" + "every?" + "some" + "not-any?" + "range" + "reverse" + "take" + "nthrest" + "partition" + "identity" + "comp" + "complement" + "constantly" + "memoize" + "assoc" + "hash-map" + "get" + "get-in" + "keys" + "vals" + "find" + "dissoc" + "remove-method" + "remove-all-methods" + "methods" + "get-method" + "hash-set"] + :name "core"}} + :order "alphabetic" + :out-dir "./doc" :project-copyright "Copyright (C) 2020-2021 Andrey Listopadov" + :project-doc-order {} :project-license "[MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE)" - :project-version "v0.5.4" + :project-version "v1.0.0" :sandbox false :test-requirements {:init-macros.fnl "(require-macros :init-macros) (import-macros {: assert-eq} :fennel-test) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bf2237..382dd41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,29 @@ -## Cljlib v0.5.5 (????-??-??) - -- Better generation of arglist docs for single-arity functions. +## Cljlib v1.0.0 (2022-08-21) +Full rewrite of the library. +This library now requires the minimum Fennel version 1.2.0. +(Fennel v1.2.0 isn't yet released at the moment of cljlib v1.0.0 release, use the build from the `main` branch). + +### New features +- added [lazy-seq](https://gitlab.com/andreyorst/lazy-seq) as a dependency, and made all sequence functions use it +- added [itable](https://gitlab.com/andreyorst/itable) as a dependency, and made all tables immutable by default +- implemented transducers +- implemented transients +- added `ns` macro + +### Changes +- `fn*` no longer splits multisyms and doesn't bind both local and namespaced versions +- `fn*` is for anonymous functions, it doesn't create a local binding +- `def` now binds in terms of the namespace, specified by `ns` +- `def` no longer support documentation metadata + +### Removed features +- removed `ordered-set` and `ordered-map` +- `into` is no longer a macro +- `empty` is no longer a macro +- removed metadata-related macros + +### Fixes +- #1 has been fixed, and `fn*` now generates multi-value destructuring when possible. ## Cljlib v0.5.4 (2021-07-22) @@ -10,7 +10,7 @@ LUASOURCES = $(FNLSOURCES:.fnl=.lua) LUAEXECUTABLES ?= lua luajit FENNELDOC := $(shell command -v fenneldoc) LUACOV_COBERTURA := $(shell command -v luacov-cobertura) -COMPILEFLAGS = --metadata +COMPILEFLAGS += --metadata .PHONY: build clean distclean test luacov luacov-console doc help $(LUAEXECUTABLES) @@ -9,7 +9,7 @@ Therefore certain functions were altered to better suit the domain. Clone library into your project or put it as a git submodule: - $ git clone https://gitlab.com/andreyorst/fennel-cljlib cljlib + $ git clone --recursive https://gitlab.com/andreyorst/fennel-cljlib cljlib Now you can require `:cljlib` from Fennel: @@ -20,9 +20,9 @@ Now you can require `:cljlib` from Fennel: Optionally precompile the library to make it load slightly faster: - $ cd cljlib; make + $ cd cljlib; COMPILEFLAGS="--require-as-include" make -This will compile `init.fnl` into `init.lua`, so `require` should honor Lua files over Fennel files. +This will compile `init.fnl` into `init.lua`, with all dependencies included, so `require` should honor Lua files over Fennel files. It is also possible to use this library from Lua this way. ## Documentation diff --git a/doc/cljlib.md b/doc/cljlib.md deleted file mode 100644 index 1e88856..0000000 --- a/doc/cljlib.md +++ /dev/null @@ -1,1263 +0,0 @@ -# Cljlib (v0.5.4) -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: - -``` lua -Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio -> clj = require"cljlib" -> table.concat(clj.mapv(function (x) return x * x end, {1, 2, 3}), " ") --- 1 4 9 -``` - -This example is mapping an anonymous `function` over a table, -producing 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. - -Each function in this library is created with `defn`, which is a -special macros 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). - -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). - -## 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. - -**Table of contents** - -- [`apply`](#apply) -- [`add`](#add) -- [`sub`](#sub) -- [`mul`](#mul) -- [`div`](#div) -- [`le`](#le) -- [`lt`](#lt) -- [`ge`](#ge) -- [`gt`](#gt) -- [`inc`](#inc) -- [`dec`](#dec) -- [`eq`](#eq) -- [`map?`](#map) -- [`vector?`](#vector) -- [`multifn?`](#multifn) -- [`set?`](#set) -- [`nil?`](#nil) -- [`zero?`](#zero) -- [`pos?`](#pos) -- [`neg?`](#neg) -- [`even?`](#even) -- [`odd?`](#odd) -- [`string?`](#string) -- [`boolean?`](#boolean) -- [`true?`](#true) -- [`false?`](#false) -- [`int?`](#int) -- [`pos-int?`](#pos-int) -- [`neg-int?`](#neg-int) -- [`double?`](#double) -- [`empty?`](#empty) -- [`not-empty`](#not-empty) -- [`vector`](#vector-1) -- [`seq`](#seq) -- [`kvseq`](#kvseq) -- [`first`](#first) -- [`rest`](#rest) -- [`last`](#last) -- [`butlast`](#butlast) -- [`conj`](#conj) -- [`disj`](#disj) -- [`cons`](#cons) -- [`concat`](#concat) -- [`reduce`](#reduce) -- [`reduced`](#reduced) -- [`reduce-kv`](#reduce-kv) -- [`mapv`](#mapv) -- [`filter`](#filter) -- [`every?`](#every) -- [`some`](#some) -- [`not-any?`](#not-any) -- [`range`](#range) -- [`reverse`](#reverse) -- [`take`](#take) -- [`nthrest`](#nthrest) -- [`partition`](#partition) -- [`identity`](#identity) -- [`comp`](#comp) -- [`complement`](#complement) -- [`constantly`](#constantly) -- [`memoize`](#memoize) -- [`assoc`](#assoc) -- [`hash-map`](#hash-map) -- [`get`](#get) -- [`get-in`](#get-in) -- [`keys`](#keys) -- [`vals`](#vals) -- [`find`](#find) -- [`dissoc`](#dissoc) -- [`remove-method`](#remove-method) -- [`remove-all-methods`](#remove-all-methods) -- [`methods`](#methods) -- [`get-method`](#get-method) -- [`ordered-set`](#ordered-set) -- [`hash-set`](#hash-set) - -## `apply` -Function signature: - -``` -(apply - ([f args]) - ([f a args]) - ([f a b args]) - ([f a b c args]) - ([f a b c d & args])) -``` - -Apply `f` to the argument list formed by prepending intervening -arguments to `args`, and `f` must support variadic amount of -arguments. - -### Examples -Applying [`add`](#add) to different amount of arguments: - -``` fennel -(assert-eq (apply add [1 2 3 4]) 10) -(assert-eq (apply add 1 [2 3 4]) 10) -(assert-eq (apply add 1 2 3 4 5 6 [7 8 9]) 45) -``` - -## `add` -Function signature: - -``` -(add ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) -``` - -Sum arbitrary amount of numbers. - -## `sub` -Function signature: - -``` -(sub ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) -``` - -Subtract arbitrary amount of numbers. - -## `mul` -Function signature: - -``` -(mul ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) -``` - -Multiply arbitrary amount of numbers. - -## `div` -Function signature: - -``` -(div ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) -``` - -Divide arbitrary amount of numbers. - -## `le` -Function signature: - -``` -(le ([a]) ([a b]) ([a b & [c d & more]])) -``` - -Returns true if nums are in monotonically non-decreasing order - -## `lt` -Function signature: - -``` -(lt ([a]) ([a b]) ([a b & [c d & more]])) -``` - -Returns true if nums are in monotonically decreasing order - -## `ge` -Function signature: - -``` -(ge ([a]) ([a b]) ([a b & [c d & more]])) -``` - -Returns true if nums are in monotonically non-increasing order - -## `gt` -Function signature: - -``` -(gt ([a]) ([a b]) ([a b & [c d & more]])) -``` - -Returns true if nums are in monotonically increasing order - -## `inc` -Function signature: - -``` -(inc [x]) -``` - -Increase number `x` by one - -## `dec` -Function signature: - -``` -(dec [x]) -``` - -Decrease number `x` by one - -## `eq` -Function signature: - -``` -(eq ([x]) ([x y]) ([x y & xs])) -``` - -Deep compare values. - -### Examples - -[`eq`](#eq) can compare both primitive types, tables, and user defined types -that have `__eq` metamethod. - -``` fennel -(assert-is (eq 42 42)) -(assert-is (eq [1 2 3] [1 2 3])) -(assert-is (eq (hash-set :a :b :c) (hash-set :a :b :c))) -(assert-is (eq (hash-set :a :b :c) (ordered-set :c :b :a))) -``` - -Deep comparison is used for tables which use tables as keys: - -``` fennel -(assert-is (eq {[1 2 3] {:a [1 2 3]} {:a 1} {:b 2}} - {{:a 1} {:b 2} [1 2 3] {:a [1 2 3]}})) -(assert-is (eq {{{:a 1} {:b 1}} {{:c 3} {:d 4}} [[1] [2 [3]]] {:a 2}} - {[[1] [2 [3]]] {:a 2} {{:a 1} {:b 1}} {{:c 3} {:d 4}}})) -``` - -## `map?` -Function signature: - -``` -(map? [tbl]) -``` - -Check whether `tbl` is an associative table. - -Non empty associative tables are tested for two things: -- `next` returns the key-value pair, -- key, that is returned by the `next` is not equal to `1`. - -Empty tables can't be analyzed with this method, and [`map?`](#map) will -return `false`. If you need this test pass for empty table, see -[`hash-map`](#hash-map) for creating tables that have additional -metadata attached for this test to work. - -### Examples -Non empty tables: - -``` fennel -(assert-is (map? {:a 1 :b 2})) - -(local some-table {:key :value}) -(assert-is (map? some-table)) -``` - -Empty tables: - -``` fennel -(local some-table {}) -(assert-not (map? some-table)) -``` - -Empty tables created with [`hash-map`](#hash-map) will pass the test: - -``` fennel -(local some-table (hash-map)) -(assert-is (map? some-table)) -``` - -## `vector?` -Function signature: - -``` -(vector? [tbl]) -``` - -Check whether `tbl` is an sequential table. - -Non empty sequential tables are tested for two things: -- `next` returns the key-value pair, -- key, that is returned by the `next` is equal to `1`. - -Empty tables can't be analyzed with this method, and [`vector?`](#vector) will -always return `false`. If you need this test pass for empty table, -see [`vector`](#vector-1) for creating tables that have additional -metadata attached for this test to work. - -### Examples -Non empty vector: - -``` fennel -(assert-is (vector? [1 2 3 4])) - -(local some-table [1 2 3]) -(assert-is (vector? some-table)) -``` - -Empty tables: - -``` fennel -(local some-table []) -(assert-not (vector? some-table)) -``` - -Empty tables created with [`vector`](#vector-1) will pass the test: - -``` fennel -(local some-table (vector)) -(assert-is (vector? some-table)) -``` - -## `multifn?` -Function signature: - -``` -(multifn? [mf]) -``` - -Test if `mf` is an instance of `multifn`. - -`multifn` is a special kind of table, created with `defmulti` macros -from `macros.fnl`. - -## `set?` -Function signature: - -``` -(set? [s]) -``` - -Test if `s` is either instance of a [`hash-set`](#hash-set) or [`ordered-set`](#ordered-set). - -## `nil?` -Function signature: - -``` -(nil? ([]) ([x])) -``` - -Test if `x` is nil. - -## `zero?` -Function signature: - -``` -(zero? [x]) -``` - -Test if `x` is equal to zero. - -## `pos?` -Function signature: - -``` -(pos? [x]) -``` - -Test if `x` is greater than zero. - -## `neg?` -Function signature: - -``` -(neg? [x]) -``` - -Test if `x` is less than zero. - -## `even?` -Function signature: - -``` -(even? [x]) -``` - -Test if `x` is even. - -## `odd?` -Function signature: - -``` -(odd? [x]) -``` - -Test if `x` is odd. - -## `string?` -Function signature: - -``` -(string? [x]) -``` - -Test if `x` is a string. - -## `boolean?` -Function signature: - -``` -(boolean? [x]) -``` - -Test if `x` is a Boolean - -## `true?` -Function signature: - -``` -(true? [x]) -``` - -Test if `x` is `true` - -## `false?` -Function signature: - -``` -(false? [x]) -``` - -Test if `x` is `false` - -## `int?` -Function signature: - -``` -(int? [x]) -``` - -Test if `x` is a number without floating point data. - -Number is rounded with `math.floor` and compared with original number. - -## `pos-int?` -Function signature: - -``` -(pos-int? [x]) -``` - -Test if `x` is a positive integer. - -## `neg-int?` -Function signature: - -``` -(neg-int? [x]) -``` - -Test if `x` is a negative integer. - -## `double?` -Function signature: - -``` -(double? [x]) -``` - -Test if `x` is a number with floating point data. - -## `empty?` -Function signature: - -``` -(empty? [x]) -``` - -Check if collection is empty. - -## `not-empty` -Function signature: - -``` -(not-empty [x]) -``` - -If `x` is empty, returns `nil`, otherwise `x`. - -## `vector` -Function signature: - -``` -(vector [& args]) -``` - -Constructs sequential table out of it's arguments. - -Sets additional metadata for function [`vector?`](#vector) to work. - -### Examples - -``` fennel -(local v (vector 1 2 3 4)) -(assert-eq v [1 2 3 4]) -``` - -## `seq` -Function signature: - -``` -(seq [col]) -``` - -Create sequential table. - -Transforms original table to sequential table of key value pairs -stored as sequential tables in linear time. If `col` is an -associative table, returns sequential table of vectors with key and -value. If `col` is sequential table, returns its shallow copy. If -`col` is string, return sequential table of its codepoints. - -### Examples -Sequential tables remain as is: - -``` fennel -(seq [1 2 3 4]) -;; [1 2 3 4] -``` - -Associative tables are transformed to format like this `[[key1 value1] -... [keyN valueN]]` and order is non deterministic: - -``` fennel -(seq {:a 1 :b 2 :c 3}) -;; [[:b 2] [:a 1] [:c 3]] -``` - -See `into` macros for transforming this back to associative table. -Additionally you can use [`conj`](#conj) and [`apply`](#apply) with -[`hash-map`](#hash-map): - -``` fennel -(apply conj (hash-map) [:c 3] [[:a 1] [:b 2]]) -;; => {:a 1 :b 2 :c 3} -``` - -## `kvseq` -Function signature: - -``` -(kvseq [col]) -``` - -Transforms any table `col` to key-value sequence. - -## `first` -Function signature: - -``` -(first [col]) -``` - -Return first element of a table. Calls [`seq`](#seq) on its argument. - -## `rest` -Function signature: - -``` -(rest [col]) -``` - -Returns table of all elements of a table but the first one. Calls - [`seq`](#seq) on its argument. - -## `last` -Function signature: - -``` -(last [col]) -``` - -Returns the last element of a table. Calls [`seq`](#seq) on its argument. - -## `butlast` -Function signature: - -``` -(butlast [col]) -``` - -Returns everything but the last element of a table as a new - table. Calls [`seq`](#seq) on its argument. - -## `conj` -Function signature: - -``` -(conj ([]) ([tbl]) ([tbl x]) ([tbl x & xs])) -``` - -Insert `x` as a last element of a table `tbl`. - -If `tbl` is a sequential table or empty table, inserts `x` and -optional `xs` as final element in the table. - -If `tbl` is an associative table, that satisfies [`map?`](#map) test, -insert `[key value]` pair into the table. - -Mutates `tbl`. - -### Examples -Adding to sequential tables: - -``` fennel -(conj [] 1 2 3 4) -;; => [1 2 3 4] -(conj [1 2 3] 4 5) -;; => [1 2 3 4 5] -``` - -Adding to associative tables: - -``` fennel -(conj {:a 1} [:b 2] [:c 3]) -;; => {:a 1 :b 2 :c 3} -``` - -Note, that passing literal empty associative table `{}` will not work: - -``` fennel -(conj {} [:a 1] [:b 2]) -;; => [[:a 1] [:b 2]] -(conj (hash-map) [:a 1] [:b 2]) -;; => {:a 1 :b 2} -``` - -See [`hash-map`](#hash-map) for creating empty associative tables. - -## `disj` -Function signature: - -``` -(disj ([s]) ([s k]) ([s k & ks])) -``` - -Remove key `k` from set `s`. - -## `cons` -Function signature: - -``` -(cons [x tbl]) -``` - -Insert `x` to `tbl` at the front. Calls [`seq`](#seq) on `tbl`. - -## `concat` -Function signature: - -``` -(concat ([]) ([x]) ([x y]) ([x y & xs])) -``` - -Concatenate tables. - -## `reduce` -Function signature: - -``` -(reduce ([f col]) ([f val col])) -``` - -Reduce collection `col` using function `f` and optional initial value `val`. - -`f` should be a function of 2 arguments. If val is not supplied, -returns the result of applying f to the first 2 items in coll, then -applying f to that result and the 3rd item, etc. If coll contains no -items, f must accept no arguments as well, and reduce returns the -result of calling f with no arguments. If coll has only 1 item, it is -returned and f is not called. If val is supplied, returns the result -of applying f to val and the first item in coll, then applying f to -that result and the 2nd item, etc. If coll contains no items, returns -val and f is not called. Calls [`seq`](#seq) on `col`. - -Early termination is possible with the use of [`reduced`](#reduced) -function. - -### Examples -Reduce sequence of numbers with [`add`](#add) - -``` fennel -(reduce add [1 2 3 4]) -;; => 10 -(reduce add 10 [1 2 3 4]) -;; => 20 -``` - -## `reduced` -Function signature: - -``` -(reduced [x]) -``` - -Wraps `x` in such a way so [`reduce`](#reduce) will terminate early -with this value. - -### Examples -Stop reduction is result is higher than `10`: - -``` fennel -(reduce (fn [res x] - (if (>= res 10) - (reduced res) - (+ res x))) - [1 2 3]) -;; => 6 - -(reduce (fn [res x] - (if (>= res 10) - (reduced res) - (+ res x))) - [1 2 3 4 :nil]) -;; => 10 -``` - -Note that in second example we had `:nil` in the array, which is not a -valid number, but we've terminated right before we've reached it. - -## `reduce-kv` -Function signature: - -``` -(reduce-kv [f val tbl]) -``` - -Reduces an associative table using function `f` and initial value `val`. - -`f` should be a function of 3 arguments. Returns the result of -applying `f` to `val`, the first key and the first value in `tbl`, -then applying `f` to that result and the 2nd key and value, etc. If -`tbl` contains no entries, returns `val` and `f` is not called. Note -that reduce-kv is supported on sequential tables and strings, where -the keys will be the ordinals. - -Early termination is possible with the use of [`reduced`](#reduced) -function. - -### Examples -Reduce associative table by adding values from all keys: - -``` fennel -(local t {:a1 1 - :b1 2 - :a2 2 - :b2 3}) - -(reduce-kv #(+ $1 $3) 0 t) -;; => 8 -``` - -Reduce table by adding values from keys that start with letter `a`: - -``` fennel -(local t {:a1 1 - :b1 2 - :a2 2 - :b2 3}) - -(reduce-kv (fn [res k v] (if (= (string.sub k 1 1) :a) (+ res v) res)) - 0 t) -;; => 3 -``` - -## `mapv` -Function signature: - -``` -(mapv - ([f col]) - ([f col1 col2]) - ([f col1 col2 col3]) - ([f col1 col2 col3 & cols])) -``` - -Maps function `f` over one or more collections. - -Accepts arbitrary amount of collections, calls [`seq`](#seq) on each of it. -Function `f` must take the same amount of arguments as the amount of -tables, passed to [`mapv`](#mapv). Applies `f` over first value of each -table. Then applies `f` to second value of each table. Continues until -any of the tables is exhausted. All remaining values are -ignored. Returns a sequential table of results. - -### Examples -Map `string.upcase` over the string: - -``` fennel -(mapv string.upper "string") -;; => ["S" "T" "R" "I" "N" "G"] -``` - -Map [`mul`](#mul) over two tables: - -``` fennel -(mapv mul [1 2 3 4] [1 0 -1]) -;; => [1 0 -3] -``` - -Basic `zipmap` implementation: - -``` fennel -(import-macros {: into} :init-macros) -(fn zipmap [keys vals] - (into {} (mapv vector keys vals))) - -(zipmap [:a :b :c] [1 2 3 4]) -;; => {:a 1 :b 2 :c 3} -``` - -## `filter` -Function signature: - -``` -(filter [pred col]) -``` - -Returns a sequential table of the items in `col` for which `pred` - returns logical true. - -## `every?` -Function signature: - -``` -(every? [pred tbl]) -``` - -Test if every item in `tbl` satisfies the `pred`. - -## `some` -Function signature: - -``` -(some [pred tbl]) -``` - -Test if any item in `tbl` satisfies the `pred`. - -## `not-any?` -Function signature: - -``` -(not-any? [pred tbl]) -``` - -Test if no item in `tbl` satisfy the `pred`. - -## `range` -Function signature: - -``` -(range ([upper]) ([lower upper]) ([lower upper step])) -``` - -return range of of numbers from `lower` to `upper` with optional `step`. - -## `reverse` -Function signature: - -``` -(reverse [tbl]) -``` - -Returns table with same items as in `tbl` but in reverse order. - -## `take` -Function signature: - -``` -(take [n col]) -``` - -Returns a sequence of the first `n` items in `col`, or all items if -there are fewer than `n`. - -## `nthrest` -Function signature: - -``` -(nthrest [col n]) -``` - -Returns the nth rest of `col`, `col` when `n` is 0. - -### Examples - -``` fennel -(assert-eq (nthrest [1 2 3 4] 3) [4]) -(assert-eq (nthrest [1 2 3 4] 2) [3 4]) -(assert-eq (nthrest [1 2 3 4] 1) [2 3 4]) -(assert-eq (nthrest [1 2 3 4] 0) [1 2 3 4]) -``` - - -## `partition` -Function signature: - -``` -(partition ([n col]) ([n step col]) ([n step pad col])) -``` - -Returns a sequence of sequences of `n` items each, at offsets step -apart. If `step` is not supplied, defaults to `n`, i.e. the partitions -do not overlap. If a `pad` collection is supplied, use its elements as -necessary to complete last partition up to `n` items. In case there -are not enough padding elements, return a partition with less than `n` -items. - -### Examples -Partition sequence into sub-sequences of size 3: - -``` fennel -(assert-eq (partition 3 [1 2 3 4 5 6]) [[1 2 3] [4 5 6]]) -``` - -When collection doesn't have enough elements, partition will not include those: - -``` fennel -(assert-eq (partition 3 [1 2 3 4]) [[1 2 3]]) -``` - -Partitions can overlap if step is supplied: - -``` fennel -(assert-eq (partition 2 1 [1 2 3 4]) [[1 2] [2 3] [3 4]]) -``` - -Additional padding can be used to supply insufficient elements: - -``` fennel -(assert-eq (partition 3 3 [3 2 1] [1 2 3 4]) [[1 2 3] [4 3 2]]) -``` - -## `identity` -Function signature: - -``` -(identity [x]) -``` - -Returns its argument. - -## `comp` -Function signature: - -``` -(comp ([]) ([f]) ([f g]) ([f g & fs])) -``` - -Compose functions. - -## `complement` -Function signature: - -``` -(complement [f]) -``` - -Takes a function `f` and returns the function that takes the same -amount of arguments as `f`, has the same effect, and returns the -oppisite truth value. - -## `constantly` -Function signature: - -``` -(constantly [x]) -``` - -Returns a function that takes any number of arguments and returns `x`. - -## `memoize` -Function signature: - -``` -(memoize [f]) -``` - -Returns a memoized version of a referentially transparent function. -The memoized version of the function keeps a cache of the mapping from -arguments to results and, when calls with the same arguments are -repeated often, has higher performance at the expense of higher memory -use. - -## `assoc` -Function signature: - -``` -(assoc ([tbl k v]) ([tbl k v & kvs])) -``` - -Associate key `k` with value `v` in `tbl`. - -## `hash-map` -Function signature: - -``` -(hash-map ([]) ([& kvs])) -``` - -Create associative table from `kvs` represented as sequence of keys -and values - -## `get` -Function signature: - -``` -(get ([tbl key]) ([tbl key not-found])) -``` - -Get value from the table by accessing it with a `key`. -Accepts additional `not-found` as a marker to return if value wasn't -found in the table. - -## `get-in` -Function signature: - -``` -(get-in ([tbl keys]) ([tbl keys not-found])) -``` - -Get value from nested set of tables by providing key sequence. -Accepts additional `not-found` as a marker to return if value wasn't -found in the table. - -## `keys` -Function signature: - -``` -(keys [tbl]) -``` - -Returns a sequence of the table's keys, in the same order as [`seq`](#seq). - -## `vals` -Function signature: - -``` -(vals [tbl]) -``` - -Returns a sequence of the table's values, in the same order as [`seq`](#seq). - -## `find` -Function signature: - -``` -(find [tbl key]) -``` - -Returns the map entry for `key`, or `nil` if key not present in `tbl`. - -## `dissoc` -Function signature: - -``` -(dissoc ([tbl]) ([tbl key]) ([tbl key & keys])) -``` - -Remove `key` from table `tbl`. Optionally takes more `keys`. - -## `remove-method` -Function signature: - -``` -(remove-method [multimethod dispatch-value]) -``` - -Remove method from `multimethod` for given `dispatch-value`. - -## `remove-all-methods` -Function signature: - -``` -(remove-all-methods [multimethod]) -``` - -Removes all of the methods of `multimethod` - -## `methods` -Function signature: - -``` -(methods [multimethod]) -``` - -Given a `multimethod`, returns a map of dispatch values -> dispatch fns - -## `get-method` -Function signature: - -``` -(get-method [multimethod dispatch-value]) -``` - -Given a `multimethod` and a `dispatch-value`, returns the dispatch -`fn` that would apply to that value, or `nil` if none apply and no -default. - -## `ordered-set` -Function signature: - -``` -(ordered-set [& xs]) -``` - -Create ordered set. - -Set is a collection of unique elements, which sore purpose is only to -tell you if something is in the set or not. - -[`ordered-set`](#ordered-set) is follows the argument insertion order, unlike sorted -sets, which apply some sorting algorithm internally. New items added -at the end of the set. Ordered set supports removal of items via -`tset` and [`disj`](#disj). To add element to the ordered set use -`tset` or [`conj`](#conj). Both operations modify the set. - -**Note**: Hash set prints as `@set{a b c}`, but this construct is not -supported by the Fennel reader, so you can't create sets with this -syntax. Use [`ordered-set`](#ordered-set) function instead. - -Below are some examples of how to create and manipulate sets. - -#### Create ordered set: -Ordered sets are created by passing any amount of elements desired to -be in the set: - -``` fennel -(ordered-set) -;; => @set{} -(ordered-set :a :c :b) -;; => @set{:a :c :b} -``` - -Duplicate items are not added: - -``` fennel -(ordered-set :a :c :a :a :a :a :c :b) -;; => @set{:a :c :b} -``` - -#### Check if set contains desired value: -Sets are functions of their keys, so simply calling a set with a -desired key will either return the key, or `nil`: - -``` fennel -(local oset (ordered-set [:a :b :c] [:c :d :e] :e :f)) -(oset [:a :b :c]) -;; => ["a" "b" "c"] -(. oset :e) -;; "e" -(oset [:a :b :f]) -;; => nil -``` - -#### Add items to existing set: -To add element to the set use [`conj`](#conj) or `tset` - -``` fennel -(local oset (ordered-set :a :b :c)) -(conj oset :d :e) -;; => @set{:a :b :c :d :e} -``` - -##### Remove items from the set: -To add element to the set use [`disj`](#disj) or `tset` - -``` fennel -(local oset (ordered-set :a :b :c)) -(disj oset :b) -;; => @set{:a :c} -(tset oset :a nil) -oset -;; => @set{:c} -``` - -#### Equality semantics -Both [`ordered-set`](#ordered-set) and [`hash-set`](#hash-set) implement `__eq` metamethod, -and are compared for having the same keys without particular order and -same size: - -``` fennel -(assert-eq (ordered-set :a :b) (ordered-set :b :a)) -(assert-ne (ordered-set :a :b) (ordered-set :b :a :c)) -(assert-eq (ordered-set :a :b) (hash-set :a :b)) -``` - -## `hash-set` -Function signature: - -``` -(hash-set [& xs]) -``` - -Create hash set. - -Set is a collection of unique elements, which sore purpose is only to -tell you if something is in the set or not. - -Hash set differs from ordered set in that the keys are do not have any -particular order. New items are added at the arbitrary position by -using [`conj`](#conj) or `tset` functions, and items can be removed -with [`disj`](#disj) or `tset` functions. Rest semantics are the same -as for [`ordered-set`](#ordered-set) - -**Note**: Hash set prints as `@set{a b c}`, but this construct is not -supported by the Fennel reader, so you can't create sets with this -syntax. Use [`hash-set`](#hash-set) function instead. - - ---- - -Copyright (C) 2020-2021 Andrey Listopadov - -License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE) - - -<!-- Generated with Fenneldoc v0.1.6 - https://gitlab.com/andreyorst/fenneldoc --> diff --git a/doc/core.md b/doc/core.md new file mode 100644 index 0000000..fa3d678 --- /dev/null +++ b/doc/core.md @@ -0,0 +1,2078 @@ +# Core (v1.0.0) +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: + +``` lua +Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio +> clj = require"cljlib" +> table.concat(clj.mapv(function (x) return x * x end, {1, 2, 3}), " ") +-- 1 4 9 +``` + +This example is mapping an anonymous `function` over a table, +producing 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. + +Each function in this library is created with `defn`, which is a +special macros 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). + +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). + +## 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. + +**Table of contents** + +- [`apply`](#apply) +- [`add`](#add) +- [`sub`](#sub) +- [`mul`](#mul) +- [`div`](#div) +- [`le`](#le) +- [`lt`](#lt) +- [`ge`](#ge) +- [`gt`](#gt) +- [`inc`](#inc) +- [`dec`](#dec) +- [`eq`](#eq) +- [`map?`](#map) +- [`vector?`](#vector) +- [`multifn?`](#multifn) +- [`set?`](#set) +- [`nil?`](#nil) +- [`zero?`](#zero) +- [`pos?`](#pos) +- [`neg?`](#neg) +- [`even?`](#even) +- [`odd?`](#odd) +- [`string?`](#string) +- [`boolean?`](#boolean) +- [`true?`](#true) +- [`false?`](#false) +- [`int?`](#int) +- [`pos-int?`](#pos-int) +- [`neg-int?`](#neg-int) +- [`double?`](#double) +- [`empty?`](#empty) +- [`not-empty`](#not-empty) +- [`vector`](#vector-1) +- [`seq`](#seq) +- [`first`](#first) +- [`rest`](#rest) +- [`last`](#last) +- [`butlast`](#butlast) +- [`conj`](#conj) +- [`disj`](#disj) +- [`cons`](#cons) +- [`concat`](#concat) +- [`reduce`](#reduce) +- [`reduced`](#reduced) +- [`reduce-kv`](#reduce-kv) +- [`mapv`](#mapv) +- [`filter`](#filter) +- [`every?`](#every) +- [`some`](#some) +- [`not-any?`](#not-any) +- [`range`](#range) +- [`reverse`](#reverse) +- [`take`](#take) +- [`nthrest`](#nthrest) +- [`partition`](#partition) +- [`identity`](#identity) +- [`comp`](#comp) +- [`complement`](#complement) +- [`constantly`](#constantly) +- [`memoize`](#memoize) +- [`assoc`](#assoc) +- [`hash-map`](#hash-map) +- [`get`](#get) +- [`get-in`](#get-in) +- [`keys`](#keys) +- [`vals`](#vals) +- [`find`](#find) +- [`dissoc`](#dissoc) +- [`remove-method`](#remove-method) +- [`remove-all-methods`](#remove-all-methods) +- [`methods`](#methods) +- [`get-method`](#get-method) +- [`hash-set`](#hash-set) +- [`assoc!`](#assoc-1) +- [`assoc-in`](#assoc-in) +- [`cat`](#cat) +- [`class`](#class) +- [`completing`](#completing) +- [`conj!`](#conj-1) +- [`contains?`](#contains) +- [`count`](#count) +- [`cycle`](#cycle) +- [`dedupe`](#dedupe) +- [`deref`](#deref) +- [`disj!`](#disj-1) +- [`dissoc!`](#dissoc-1) +- [`distinct`](#distinct) +- [`doall`](#doall) +- [`dorun`](#dorun) +- [`drop`](#drop) +- [`drop-last`](#drop-last) +- [`drop-while`](#drop-while) +- [`empty`](#empty-1) +- [`ensure-reduced`](#ensure-reduced) +- [`filterv`](#filterv) +- [`frequencies`](#frequencies) +- [`group-by`](#group-by) +- [`halt-when`](#halt-when) +- [`interleave`](#interleave) +- [`interpose`](#interpose) +- [`into`](#into) +- [`iterate`](#iterate) +- [`keep`](#keep) +- [`keep-indexed`](#keep-indexed) +- [`lazy-seq`](#lazy-seq) +- [`line-seq`](#line-seq) +- [`list`](#list) +- [`list*`](#list-1) +- [`map`](#map-1) +- [`map-indexed`](#map-indexed) +- [`mapcat`](#mapcat) +- [`merge`](#merge) +- [`next`](#next) +- [`nth`](#nth) +- [`nthnext`](#nthnext) +- [`partition-all`](#partition-all) +- [`partition-by`](#partition-by) +- [`persistent!`](#persistent) +- [`pop!`](#pop) +- [`random-sample`](#random-sample) +- [`realized?`](#realized) +- [`reduced?`](#reduced-1) +- [`reductions`](#reductions) +- [`remove`](#remove) +- [`repeat`](#repeat) +- [`repeatedly`](#repeatedly) +- [`replace`](#replace) +- [`rseq`](#rseq) +- [`seq?`](#seq-1) +- [`sequence`](#sequence) +- [`some?`](#some-1) +- [`sort`](#sort) +- [`split-at`](#split-at) +- [`split-with`](#split-with) +- [`take-last`](#take-last) +- [`take-nth`](#take-nth) +- [`take-while`](#take-while) +- [`transduce`](#transduce) +- [`transient`](#transient) +- [`tree-seq`](#tree-seq) +- [`unreduced`](#unreduced) +- [`update`](#update) +- [`update-in`](#update-in) +- [`vec`](#vec) +- [`zipmap`](#zipmap) + +## `apply` +Function signature: + +``` +(apply ([f args]) ([f a args]) ([f a b args]) ([f a b c args]) ([f a b c d & args])) +``` + +Apply `f` to the argument list formed by prepending intervening +arguments to `args`, and `f` must support variadic amount of +arguments. + +### Examples +Applying `add` to different amount of arguments: + +``` fennel +(assert-eq (apply add [1 2 3 4]) 10) +(assert-eq (apply add 1 [2 3 4]) 10) +(assert-eq (apply add 1 2 3 4 5 6 [7 8 9]) 45) +``` + +## `add` +Function signature: + +``` +(add ({}) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) +``` + +Sum arbitrary amount of numbers. + +## `sub` +Function signature: + +``` +(sub ({}) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) +``` + +Subtract arbitrary amount of numbers. + +## `mul` +Function signature: + +``` +(mul ({}) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) +``` + +Multiply arbitrary amount of numbers. + +## `div` +Function signature: + +``` +(div ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) +``` + +Divide arbitrary amount of numbers. + +## `le` +Function signature: + +``` +(le ([a]) ([a b]) ([a b & [c d & more]])) +``` + +Returns true if nums are in monotonically non-decreasing order + +## `lt` +Function signature: + +``` +(lt ([a]) ([a b]) ([a b & [c d & more]])) +``` + +Returns true if nums are in monotonically decreasing order + +## `ge` +Function signature: + +``` +(ge ([a]) ([a b]) ([a b & [c d & more]])) +``` + +Returns true if nums are in monotonically non-increasing order + +## `gt` +Function signature: + +``` +(gt ([a]) ([a b]) ([a b & [c d & more]])) +``` + +Returns true if nums are in monotonically increasing order + +## `inc` +Function signature: + +``` +(inc [x]) +``` + +Increase number `x` by one + +## `dec` +Function signature: + +``` +(dec [x]) +``` + +Decrease number `x` by one + +## `eq` +Function signature: + +``` +(eq ({}) ([_]) ([a b]) ([a b & cs])) +``` + +Comparison function. + +Accepts arbitrary amount of values, and does the deep comparison. If +values implement `__eq` metamethod, tries to use it, by checking if +first value is equal to second value, and the second value is equal to +the first value. If values are not equal and are tables does the deep +comparison. Tables as keys are supported. + +## `map?` +Function signature: + +``` +(map? [x]) +``` + +Check whether `x` is an associative table. + +Non-empty tables are tested by calling `next`. If the length of the +table is greater than zero, the last integer key is passed to the +`next`, and if `next` returns a key, the table is considered +associative. If the length is zero, `next` is called with what `paris` +returns for the table, and if the key is returned, table is considered +associative. + +Empty tables can't be analyzed with this method, and `map?` will +always return `false`. If you need this test pass for empty table, +see `hash-map` for creating tables that have additional metadata +attached for this test to work. + +### Examples +Non empty map: + +``` fennel +(assert-is (map? {:a 1 :b 2})) +``` + +Empty tables don't pass the test: + +``` fennel +(assert-not (map? {})) +``` + +Empty tables created with `hash-map` will pass the test: + +``` fennel +(assert-is (map? (hash-map))) +``` + +## `vector?` +Function signature: + +``` +(vector? [x]) +``` + +Check whether `tbl` is an sequential table. + +Non empty sequential tables are tested for two things: +- `next` returns the key-value pair, +- key, that is returned by the `next` is equal to `1`. + +Empty tables can't be analyzed with this method, and `vector?` will +always return `false`. If you need this test pass for empty table, +see `vector` for creating tables that have additional +metadata attached for this test to work. + +### Examples +Non empty vector: + +``` fennel +(assert-is (vector? [1 2 3 4])) +``` + +Empty tables don't pass the test: + +``` fennel +(assert-not (vector? [])) +``` + +Empty tables created with `vector` will pass the test: + +``` fennel +(assert-is (vector? (vector))) +``` + +## `multifn?` +Function signature: + +``` +(multifn? [mf]) +``` + +Test if `mf` is an instance of `multifn`. + +`multifn` is a special kind of table, created with `defmulti` macros +from `macros.fnl`. + +## `set?` +Function signature: + +``` +(set? [x]) +``` + +Check if object is a set. + +## `nil?` +Function signature: + +``` +(nil? ({}) ([x])) +``` + +Test if `x` is nil. + +## `zero?` +Function signature: + +``` +(zero? [x]) +``` + +Test if `x` is equal to zero. + +## `pos?` +Function signature: + +``` +(pos? [x]) +``` + +Test if `x` is greater than zero. + +## `neg?` +Function signature: + +``` +(neg? [x]) +``` + +Test if `x` is less than zero. + +## `even?` +Function signature: + +``` +(even? [x]) +``` + +Test if `x` is even. + +## `odd?` +Function signature: + +``` +(odd? [x]) +``` + +Test if `x` is odd. + +## `string?` +Function signature: + +``` +(string? [x]) +``` + +Test if `x` is a string. + +## `boolean?` +Function signature: + +``` +(boolean? [x]) +``` + +Test if `x` is a Boolean + +## `true?` +Function signature: + +``` +(true? [x]) +``` + +Test if `x` is `true` + +## `false?` +Function signature: + +``` +(false? [x]) +``` + +Test if `x` is `false` + +## `int?` +Function signature: + +``` +(int? [x]) +``` + +Test if `x` is a number without floating point data. + +Number is rounded with `math.floor` and compared with original number. + +## `pos-int?` +Function signature: + +``` +(pos-int? [x]) +``` + +Test if `x` is a positive integer. + +## `neg-int?` +Function signature: + +``` +(neg-int? [x]) +``` + +Test if `x` is a negative integer. + +## `double?` +Function signature: + +``` +(double? [x]) +``` + +Test if `x` is a number with floating point data. + +## `empty?` +Function signature: + +``` +(empty? [x]) +``` + +Check if collection is empty. + +## `not-empty` +Function signature: + +``` +(not-empty [x]) +``` + +If `x` is empty, returns `nil`, otherwise `x`. + +## `vector` +Function signature: + +``` +(vector [& args]) +``` + +Constructs sequential table out of it's arguments. + +Sets additional metadata for function `vector?` to work. + +### Examples + +``` fennel +(def :private v (vector 1 2 3 4)) +(assert-eq v [1 2 3 4]) +``` + +## `seq` +Function signature: + +``` +(seq [coll]) +``` + +Construct a sequnce from the given collection `coll`. If `coll` is an +associative table, returns sequence of vectors with key and +value. If `col` is sequential table, returns its shallow copy. If +`col` is string, return sequential table of its codepoints. + +### Examples +Sequential tables are transformed to sequences: + +``` fennel +(seq [1 2 3 4]) ;; @seq(1 2 3 4) +``` + +Associative tables are transformed to format like this `[[key1 value1] +... [keyN valueN]]` and order is non deterministic: + +``` fennel +(seq {:a 1 :b 2 :c 3}) ;; @seq([:b 2] [:a 1] [:c 3]) +``` + +## `first` +Function signature: + +``` +(first [coll]) +``` + +Return first element of a `coll`. Calls `seq` on its argument. + +## `rest` +Function signature: + +``` +(rest [coll]) +``` + +Returns a sequence of all elements of a `coll` but the first one. +Calls `seq` on its argument. + +## `last` +Function signature: + +``` +(last [coll]) +``` + +Returns the last element of a `coll`. Calls `seq` on its argument. + +## `butlast` +Function signature: + +``` +(butlast [coll]) +``` + +Returns everything but the last element of the `coll` as a new + sequence. Calls `seq` on its argument. + +## `conj` +Function signature: + +``` +(conj ({}) ([s]) ([s x]) ([s x & xs])) +``` + +Insert `x` as a last element of a table `tbl`. + +If `tbl` is a sequential table or empty table, inserts `x` and +optional `xs` as final element in the table. + +If `tbl` is an associative table, that satisfies `map?` test, +insert `[key value]` pair into the table. + +Mutates `tbl`. + +### Examples +Adding to sequential tables: + +``` fennel +(conj [] 1 2 3 4) +;; => [1 2 3 4] +(conj [1 2 3] 4 5) +;; => [1 2 3 4 5] +``` + +Adding to associative tables: + +``` fennel +(conj {:a 1} [:b 2] [:c 3]) +;; => {:a 1 :b 2 :c 3} +``` + +Note, that passing literal empty associative table `{}` will not work: + +``` fennel +(conj {} [:a 1] [:b 2]) +;; => [[:a 1] [:b 2]] +(conj (hash-map) [:a 1] [:b 2]) +;; => {:a 1 :b 2} +``` + +See `hash-map` for creating empty associative tables. + +## `disj` +Function signature: + +``` +(disj ([Set]) ([Set key]) ([Set key & keys])) +``` + +Returns a new set type, that does not contain the +specified `key` or `keys`. + +## `cons` +Function signature: + +``` +(cons [head tail]) +``` + +Construct a cons cell. +Prepends new `head` to a `tail`, which must be either a table, +sequence, or nil. + +### Examples + +``` fennel +(assert-eq [0 1] (cons 0 [1])) +(assert-eq (list 0 1 2 3) (cons 0 (cons 1 (list 2 3)))) +``` + +## `concat` +Function signature: + +``` +(concat [& colls]) +``` + +Return a lazy sequence of concatenated `colls`. + +## `reduce` +Function signature: + +``` +(reduce ([f coll]) ([f val coll])) +``` + +`f` should be a function of 2 arguments. If `val` is not supplied, +returns the result of applying `f` to the first 2 items in `coll`, +then applying `f` to that result and the 3rd item, etc. If `coll` +contains no items, f must accept no arguments as well, and reduce +returns the result of calling `f` with no arguments. If `coll` has +only 1 item, it is returned and `f` is not called. If `val` is +supplied, returns the result of applying `f` to `val` and the first +item in `coll`, then applying `f` to that result and the 2nd item, +etc. If `coll` contains no items, returns `val` and `f` is not +called. Early termination is supported via `reduced`. + +### Examples + +``` fennel +(defn- add + ([] 0) + ([a] a) + ([a b] (+ a b)) + ([a b & cs] (apply add (+ a b) cs))) +;; no initial value +(assert-eq 10 (reduce add [1 2 3 4])) +;; initial value +(assert-eq 10 (reduce add 1 [2 3 4])) +;; empty collection - function is called with 0 args +(assert-eq 0 (reduce add [])) +(assert-eq 10.3 (reduce math.floor 10.3 [])) +;; collection with a single element doesn't call a function unless the +;; initial value is supplied +(assert-eq 10.3 (reduce math.floor [10.3])) +(assert-eq 7 (reduce add 3 [4])) +``` + +## `reduced` +Function signature: + +``` +(reduced [value]) +``` + +Terminates the `reduce` early with a given `value`. + +### Examples + +``` fennel +(assert-eq :NaN + (reduce (fn [acc x] + (if (not= :number (type x)) + (reduced :NaN) + (+ acc x))) + [1 2 :3 4 5])) +``` + +## `reduce-kv` +Function signature: + +``` +(reduce-kv [f val s]) +``` + +Reduces an associative table using function `f` and initial value `val`. + +`f` should be a function of 3 arguments. Returns the result of +applying `f` to `val`, the first key and the first value in `tbl`, +then applying `f` to that result and the 2nd key and value, etc. If +`tbl` contains no entries, returns `val` and `f` is not called. Note +that reduce-kv is supported on sequential tables and strings, where +the keys will be the ordinals. + +Early termination is possible with the use of `reduced` +function. + +### Examples +Reduce associative table by adding values from all keys: + +``` fennel +(local t {:a1 1 + :b1 2 + :a2 2 + :b2 3}) + +(reduce-kv #(+ $1 $3) 0 t) +;; => 8 +``` + +Reduce table by adding values from keys that start with letter `a`: + +``` fennel +(local t {:a1 1 + :b1 2 + :a2 2 + :b2 3}) + +(reduce-kv (fn [res k v] (if (= (string.sub k 1 1) :a) (+ res v) res)) + 0 t) +;; => 3 +``` + +## `mapv` +Function signature: + +``` +(mapv ([f coll]) ([f coll & colls])) +``` + +Returns a vector consisting of the result of applying `f` to the +set of first items of each `coll`, followed by applying `f` to the set +of second items in each coll, until any one of the `colls` is exhausted. +Any remaining items in other colls are ignored. Function `f` should +accept number-of-colls arguments. + +## `filter` +Function signature: + +``` +(filter ([pred]) ([pred coll])) +``` + +Returns a lazy sequence of the items in `coll` for which +`pred` returns logical true. Returns a transducer when no collection +is provided. + +## `every?` +Function signature: + +``` +(every? [pred coll]) +``` + +Test if every item in `coll` satisfies the `pred`. + +## `some` +Function signature: + +``` +(some [pred coll]) +``` + +Test if any item in `coll` satisfies the `pred`. + +## `not-any?` +Function signature: + +``` +(not-any? [pred coll]) +``` + +Test if no item in `coll` satisfy the `pred`. + +## `range` +Function signature: + +``` +(range ({}) ([upper]) ([lower upper]) ([lower upper step])) +``` + +Returns lazy sequence of of numbers from `lower` to `upper` with optional `step`. + +## `reverse` +Function signature: + +``` +(reverse [coll]) +``` + +Returns a lazy sequnce with same items as in `coll` but in reverse order. + +## `take` +Function signature: + +``` +(take ([n]) ([n coll])) +``` + +Returns a lazy sequence of the first `n` items in `coll`, or all items if +there are fewer than `n`. + +## `nthrest` +Function signature: + +``` +(nthrest [coll n]) +``` + +Returns the nth rest of `coll`, `coll` when `n` is 0. + +### Examples + +``` fennel +(assert-eq (nthrest [1 2 3 4] 3) [4]) +(assert-eq (nthrest [1 2 3 4] 2) [3 4]) +(assert-eq (nthrest [1 2 3 4] 1) [2 3 4]) +(assert-eq (nthrest [1 2 3 4] 0) [1 2 3 4]) +``` + +## `partition` +Function signature: + +``` +(partition ([n coll]) ([n step coll]) ([n step pad coll])) +``` + +Given a collection `coll`, returns a lazy sequence of lists of `n` +items each, at offsets `step` apart. If `step` is not supplied, +defaults to `n`, i.e. the partitions do not overlap. If a `pad` +collection is supplied, use its elements as necessary to complete last +partition upto `n` items. In case there are not enough padding +elements, return a partition with less than `n` items. + +## `identity` +Function signature: + +``` +(identity [x]) +``` + +Returns its argument. + +## `comp` +Function signature: + +``` +(comp ({}) ([f]) ([f g]) ([f g & fs])) +``` + +Compose functions. + +## `complement` +Function signature: + +``` +(complement [f]) +``` + +Takes a function `f` and returns the function that takes the same +amount of arguments as `f`, has the same effect, and returns the +oppisite truth value. + +## `constantly` +Function signature: + +``` +(constantly [x]) +``` + +Returns a function that takes any number of arguments and returns `x`. + +## `memoize` +Function signature: + +``` +(memoize [f]) +``` + +Returns a memoized version of a referentially transparent function. +The memoized version of the function keeps a cache of the mapping from +arguments to results and, when calls with the same arguments are +repeated often, has higher performance at the expense of higher memory +use. + +## `assoc` +Function signature: + +``` +(assoc ([tbl]) ([tbl k v]) ([tbl k v & kvs])) +``` + +Associate `val` under a `key`. +Accepts extra keys and values. + +### Examples + +``` fennel +(assert-eq {:a 1 :b 2} (assoc {:a 1} :b 2)) +(assert-eq {:a 1 :b 2} (assoc {:a 1 :b 1} :b 2)) +(assert-eq {:a 1 :b 2 :c 3} (assoc {:a 1 :b 1} :b 2 :c 3)) +``` + +## `hash-map` +Function signature: + +``` +(hash-map [& kvs]) +``` + +Create associative table from `kvs` represented as sequence of keys +and values + +## `get` +Function signature: + +``` +(get ([tbl key]) ([tbl key not-found])) +``` + +Get value from the table by accessing it with a `key`. +Accepts additional `not-found` as a marker to return if value wasn't +found in the table. + +## `get-in` +Function signature: + +``` +(get-in ([tbl keys]) ([tbl keys not-found])) +``` + +Get value from nested set of tables by providing key sequence. +Accepts additional `not-found` as a marker to return if value wasn't +found in the table. + +## `keys` +Function signature: + +``` +(keys [coll]) +``` + +Returns a sequence of the map's keys, in the same order as `seq`. + +## `vals` +Function signature: + +``` +(vals [coll]) +``` + +Returns a sequence of the table's values, in the same order as `seq`. + +## `find` +Function signature: + +``` +(find [coll key]) +``` + +Returns the map entry for `key`, or `nil` if key not present in `coll`. + +## `dissoc` +Function signature: + +``` +(dissoc ([tbl]) ([tbl key]) ([tbl key & keys])) +``` + +Remove `key` from table `tbl`. Optionally takes more `keys`. + +## `remove-method` +Function signature: + +``` +(remove-method [multimethod dispatch-value]) +``` + +Remove method from `multimethod` for given `dispatch-value`. + +## `remove-all-methods` +Function signature: + +``` +(remove-all-methods [multimethod]) +``` + +Removes all of the methods of `multimethod` + +## `methods` +Function signature: + +``` +(methods [multimethod]) +``` + +Given a `multimethod`, returns a map of dispatch values -> dispatch fns + +## `get-method` +Function signature: + +``` +(get-method [multimethod dispatch-value]) +``` + +Given a `multimethod` and a `dispatch-value`, returns the dispatch +`fn` that would apply to that value, or `nil` if none apply and no +default. + +## `hash-set` +Function signature: + +``` +(hash-set [& xs]) +``` + +Create hash set. + +Set is a collection of unique elements, which sore purpose is only to +tell you if something is in the set or not. + +## `assoc!` +Function signature: + +``` +(assoc! [map k & ks]) +``` + +Remove `k`from transient map, and return `map`. + +## `assoc-in` +Function signature: + +``` +(assoc-in [tbl key-seq val]) +``` + +Associate `val` into set of immutable nested tables `t`, via given `key-seq`. +Returns a new immutable table. Returns a new immutable table. + +### Examples + +Replace value under nested keys: + +``` fennel +(assert-eq + {:a {:b {:c 1}}} + (assoc-in {:a {:b {:c 0}}} [:a :b :c] 1)) +``` + +Create new entries as you go: + +``` fennel +(assert-eq + {:a {:b {:c 1}} :e 2} + (assoc-in {:e 2} [:a :b :c] 1)) +``` + +## `cat` +Function signature: + +``` +(cat [rf]) +``` + +A transducer which concatenates the contents of each input, which must be a + collection, into the reduction. + +## `class` +Function signature: + +``` +(class [x]) +``` + +Return cljlib type of the `x`, or lua type. + +## `completing` +Function signature: + +``` +(completing ([f]) ([f cf])) +``` + +Takes a reducing function `f` of 2 args and returns a function +suitable for transduce by adding an arity-1 signature that calls +`cf` (default - `identity`) on the result argument. + +## `conj!` +Function signature: + +``` +(conj! ({}) ([coll]) ([coll x])) +``` + +Adds `x` to the transient collection, and return `coll`. + +## `contains?` +Function signature: + +``` +(contains? [coll elt]) +``` + +Test if `elt` is in the `coll`. May be a linear search depending on the type of the collection. + +## `count` +Function signature: + +``` +(count [s]) +``` + +Count amount of elements in the sequence. + +## `cycle` +Function signature: + +``` +(cycle [coll]) +``` + +Create a lazy infinite sequence of repetitions of the items in the +`coll`. + +## `dedupe` +Function signature: + +``` +(dedupe ({}) ([coll])) +``` + +Returns a lazy sequence removing consecutive duplicates in coll. +Returns a transducer when no collection is provided. + +## `deref` +Function signature: + +``` +(deref [x]) +``` + +Dereference an object. + +## `disj!` +Function signature: + +``` +(disj! ([Set]) ([Set key & ks])) +``` + +disj[oin]. Returns a transient set of the same type, that does not +contain `key`. + +## `dissoc!` +Function signature: + +``` +(dissoc! [map k & ks]) +``` + +Remove `k`from transient map, and return `map`. + +## `distinct` +Function signature: + +``` +(distinct ({}) ([coll])) +``` + +Returns a lazy sequence of the elements of the `coll` without +duplicates. Comparison is done by equality. Returns a transducer when +no collection is provided. + +## `doall` +Function signature: + +``` +(doall [seq]) +``` + +Realize whole lazy sequence `seq`. + +Walks whole sequence, realizing each cell. Use at your own risk on +infinite sequences. + +## `dorun` +Function signature: + +``` +(dorun [seq]) +``` + +Realize whole sequence `seq` for side effects. + +Walks whole sequence, realizing each cell. Use at your own risk on +infinite sequences. + +## `drop` +Function signature: + +``` +(drop ([n]) ([n coll])) +``` + +Drop `n` elements from collection `coll`, returning a lazy sequence +of remaining elements. Returns a transducer when no collection is +provided. + +## `drop-last` +Function signature: + +``` +(drop-last ({}) ([coll]) ([n coll])) +``` + +Return a lazy sequence from `coll` without last `n` elements. + +## `drop-while` +Function signature: + +``` +(drop-while ([pred]) ([pred coll])) +``` + +Drop the elements from the collection `coll` until `pred` returns logical +false for any of the elemnts. Returns a lazy sequence. Returns a +transducer when no collection is provided. + +## `empty` +Function signature: + +``` +(empty [x]) +``` + +Get an empty variant of a given collection. + +## `ensure-reduced` +Function signature: + +``` +(ensure-reduced [x]) +``` + +If x is already reduced?, returns it, else returns (reduced x) + +## `filterv` +Function signature: + +``` +(filterv [pred coll]) +``` + +Returns a vector of the items in `coll` for which +`pred` returns logical true. + +## `frequencies` +Function signature: + +``` +(frequencies [t]) +``` + +Return a table of unique entries from table `t` associated to amount +of their appearances. + +### Examples + +Count each entry of a random letter: + +``` fennel +(let [fruits [:banana :banana :apple :strawberry :apple :banana]] + (assert-eq (frequencies fruits) + {:banana 3 + :apple 2 + :strawberry 1})) +``` + +## `group-by` +Function signature: + +``` +(group-by [f t]) +``` + +Group table items in an associative table under the keys that are +results of calling `f` on each element of sequential table `t`. +Elements that the function call resulted in `nil` returned in a +separate table. + +### Examples + +Group rows by their date: + +``` fennel +(local rows + [{:date "2007-03-03" :product "pineapple"} + {:date "2007-03-04" :product "pizza"} + {:date "2007-03-04" :product "pineapple pizza"} + {:date "2007-03-05" :product "bananas"}]) + +(assert-eq (group-by #(. $ :date) rows) + {"2007-03-03" + [{:date "2007-03-03" :product "pineapple"}] + "2007-03-04" + [{:date "2007-03-04" :product "pizza"} + {:date "2007-03-04" :product "pineapple pizza"}] + "2007-03-05" + [{:date "2007-03-05" :product "bananas"}]}) +``` + +## `halt-when` +Function signature: + +``` +(halt-when ([pred]) ([pred retf])) +``` + +Returns a transducer that ends transduction when `pred` returns `true` +for an input. When `retf` is supplied it must be a `fn` of 2 arguments +- it will be passed the (completed) result so far and the input that +triggered the predicate, and its return value (if it does not throw an +exception) will be the return value of the transducer. If `retf` is +not supplied, the input that triggered the predicate will be +returned. If the predicate never returns `true` the transduction is +unaffected. + +## `interleave` +Function signature: + +``` +(interleave ({}) ([s]) ([s1 s2]) ([s1 s2 & ss])) +``` + +Returns a lazy sequence of the first item in each sequence, then the +second one, until any sequence exhausts. + +## `interpose` +Function signature: + +``` +(interpose ([sep]) ([separator coll])) +``` + +Returns a lazy sequence of the elements of `coll` separated by +`separator`. Returns a transducer when no collection is provided. + +## `into` +Function signature: + +``` +(into ({}) ([to]) ([to from]) ([to xform from])) +``` + +Returns a new coll consisting of to-coll with all of the items of + from-coll conjoined. A transducer may be supplied. + +### Examples + +Thransofmr a hash-map into a sequence of key-value pairs: + +```fennel +(assert-eq [[:a 1]] (into (vector) {:a 1})) +``` + + Construct a hash-map from a sequence of key-value pairs: + +```fennel +(assert-eq {:a 1 :b 2 :c 3} + (into (hash-map) [[:a 1] [:b 2] [:c 3]])) +``` + +## `iterate` +Function signature: + +``` +(iterate [f x]) +``` + +Returns an infinete lazy sequence of x, (f x), (f (f x)) etc. + +## `keep` +Function signature: + +``` +(keep ([f]) ([f coll])) +``` + +Returns a lazy sequence of the non-nil results of calling `f` on the +items of the `coll`. Returns a transducer when no collection is +provided. + +## `keep-indexed` +Function signature: + +``` +(keep-indexed ([f]) ([f coll])) +``` + +Returns a lazy sequence of the non-nil results of (f index item) in +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: + +``` +(line-seq [file]) +``` + +Accepts a `file` handle, and creates a lazy sequence of lines using +`lines` metamethod. + +### Examples + +Lazy sequence of file lines may seem similar to an iterator over a +file, but the main difference is that sequence can be shared onve +realized, and iterator can't. Lazy sequence can be consumed in +iterator style with the `doseq` macro. + +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)] + (line-seq f))] + ;; this errors because only first line was realized, but the file + ;; was closed before the rest of lines were cached + (assert-not (pcall next lines))) +``` + +Sequence is realized with `doall` before file was closed and can be shared: + +``` fennel +(let [lines (with-open [f (io.open "init.fnl" :r)] + (doall (line-seq f)))] + (assert-is (pcall next lines))) +``` + +Infinite files can't be fully realized, but can be partially realized +with `take`: + +``` fennel +(let [lines (with-open [f (io.open "/dev/urandom" :r)] + (doall (take 3 (line-seq f))))] + (assert-is (pcall next lines))) +``` + +## `list` +Function signature: + +``` +(list ...) +``` + +Create eager sequence of provided values. + +### Examples + +``` fennel +(local l (list 1 2 3 4 5)) +(assert-eq [1 2 3 4 5] l) +``` + +## `list*` +Function signature: + +``` +(list* [& args]) +``` + +Creates a new sequence containing the items prepended to the rest, +the last of which will be treated as a sequence. + +### Examples + +``` fennel +(local l (list* 1 2 3 [4 5])) +(assert-eq [1 2 3 4 5] l) +``` + +## `map` +Function signature: + +``` +(map ([f]) ([f coll]) ([f coll & colls])) +``` + +Returns a lazy sequence consisting of the result of applying `f` to +the set of first items of each `coll`, followed by applying `f` to the +set of second items in each `coll`, until any one of the `colls` is +exhausted. Any remaining items in other `colls` are ignored. Function +`f` should accept number-of-colls arguments. Returns a transducer when +no collection is provided. + +### Examples + +```fennel +(map #(+ $ 1) [1 2 3]) ;; => @seq(2 3 4) +(map #(+ $1 $2) [1 2 3] [4 5 6]) ;; => @seq(5 7 9) +(def :private res (map #(+ $ 1) [:a :b :c])) ;; will raise an error only when realized +``` + +## `map-indexed` +Function signature: + +``` +(map-indexed ([f]) ([f coll])) +``` + +Returns a lazy sequence consisting of the result of applying `f` to 1 +and the first item of `coll`, followed by applying `f` to 2 and the +second item in `coll`, etc, until `coll` is exhausted. Returns a +transducer when no collection is provided. + +## `mapcat` +Function signature: + +``` +(mapcat ([f]) ([f & colls])) +``` + +Apply `concat` to the result of calling `map` with `f` and +collections `colls`. Returns a transducer when no collection is +provided. + +## `merge` +Function signature: + +``` +(merge [& maps]) +``` + +Merge `maps` rght to left into a single hash-map. + +## `next` +Function signature: + +``` +(next [s]) +``` + +Return the tail of a sequence. + +If the sequence is empty, returns nil. + +## `nth` +Function signature: + +``` +(nth ([coll i]) ([coll i not-found])) +``` + +Returns the value at the `index`. `get` returns `nil` if `index` out +of bounds, `nth` raises an error unless `not-found` is supplied. +`nth` also works for strings and sequences. + +## `nthnext` +Function signature: + +``` +(nthnext [coll n]) +``` + +Returns the nth next of `coll`, (seq coll) when `n` is 0. + +## `partition-all` +Function signature: + +``` +(partition-all ([n]) ([n coll]) ([n step coll])) +``` + +Given a collection `coll`, returns a lazy sequence of lists like +`partition`, but may include partitions with fewer than n items at the +end. Accepts addiitonal `step` argument, similarly to `partition`. +Returns a transducer, if collection is not supplied. + +## `partition-by` +Function signature: + +``` +(partition-by ([f]) ([f coll])) +``` + +Applies `f` to each value in `coll`, splitting it each time `f` +returns a new value. Returns a lazy seq of partitions. Returns a +transducer, if collection is not supplied. + +## `persistent!` +Function signature: + +``` +(persistent! [coll]) +``` + +Returns a new, persistent version of the transient collection. The +transient collection cannot be used after this call, any such use will +raise an error. + +## `pop!` +Function signature: + +``` +(pop! [coll]) +``` + +Removes the last item from a transient vector. If the collection is +empty, raises an error Returns coll + +## `random-sample` +Function signature: + +``` +(random-sample ([prob]) ([prob coll])) +``` + +Returns items from coll with random probability of prob (0.0 - +1.0). Returns a transducer when no collection is provided. + +## `realized?` +Function signature: + +``` +(realized? [s]) +``` + +Check if sequence's first element is realized. + +## `reduced?` +Function signature: + +``` +(reduced? [x]) +``` + +Returns true if `x` is the result of a call to reduced + +## `reductions` +Function signature: + +``` +(reductions ([f coll]) ([f init coll])) +``` + +Returns a lazy seq of the intermediate values of the reduction (as +per reduce) of `coll` by `f`, starting with `init`. + +## `remove` +Function signature: + +``` +(remove ([pred]) ([pred coll])) +``` + +Returns a lazy sequence of the items in the `coll` without elements +for wich `pred` returns logical true. Returns a transducer when no +collection is provided. + +## `repeat` +Function signature: + +``` +(repeat [x]) +``` + +Takes a value `x` and returns an infinite lazy sequence of this value. + +### Examples + +``` fennel +(assert-eq 10 (accumulate [res 0 + _ x (pairs (take 10 (repeat 1)))] + (+ res x))) +``` + +## `repeatedly` +Function signature: + +``` +(repeatedly [f & args]) +``` + +Takes a function `f` and returns an infinite lazy sequence of +function applications. Rest arguments are passed to the function. + +## `replace` +Function signature: + +``` +(replace ([smap]) ([smap coll])) +``` + +Given a map of replacement pairs and a vector/collection `coll`, +returns a vector/seq with any elements `=` a key in `smap` replaced +with the corresponding `val` in `smap`. Returns a transducer when no +collection is provided. + +## `rseq` +Function signature: + +``` +(rseq [rev]) +``` + +Returns, in possibly-constant time, a seq of the items in `rev` in reverse order. +Input must be traversable with `ipairs`. Doesn't work in constant +time if `rev` implements a linear-time `__len` metamethod, or invoking +Lua `#` operator on `rev` takes linar time. If `t` is empty returns +`nil`. + +### Examples + +``` fennel +(def :private v [1 2 3]) +(def :private r (rseq v)) + +(assert-eq (reverse v) r) +``` + +## `seq?` +Function signature: + +``` +(seq? [x]) +``` + +Check if object is a sequence. + +## `sequence` +Function signature: + +``` +(sequence ([coll]) ([xform coll]) ([xform coll & colls])) +``` + +Coerces coll to a (possibly empty) sequence, if it is not already +one. Will not force a lazy seq. `(sequence nil)` yields an empty list, +When a transducer is supplied, returns a lazy sequence of applications +of the transform to the items in `coll`, i.e. to the set of first +items of each `coll`, followed by the set of second items in each +`coll`, until any one of the `colls` is exhausted. Any remaining +items in other `colls` are ignored. The transform should accept +number-of-colls arguments + +## `some?` +Function signature: + +``` +(some? [x]) +``` + +Returns true if x is not nil, false otherwise. + +## `sort` +Function signature: + +``` +(sort ([coll]) ([comparator coll])) +``` + +Returns a sorted sequence of the items in `coll`. If no `comparator` +is supplied, uses `<`. + +## `split-at` +Function signature: + +``` +(split-at [n coll]) +``` + +Return a table with sequence `coll` being split at `n` + +## `split-with` +Function signature: + +``` +(split-with [pred coll]) +``` + +Return a table with sequence `coll` being split with `pred` + +## `take-last` +Function signature: + +``` +(take-last [n coll]) +``` + +Return a sequence of last `n` elements of the `coll`. + +## `take-nth` +Function signature: + +``` +(take-nth ([n]) ([n coll])) +``` + +Return a lazy sequence of every `n` item in `coll`. Returns a +transducer when no collection is provided. + +## `take-while` +Function signature: + +``` +(take-while ([pred]) ([pred coll])) +``` + +Take the elements from the collection `coll` until `pred` returns logical +false for any of the elemnts. Returns a lazy sequence. Returns a +transducer when no collection is provided. + +## `transduce` +Function signature: + +``` +(transduce ([xform f coll]) ([xform f init coll])) +``` + +`reduce` with a transformation of `f` (`xform`). If `init` is not +supplied, `f` will be called to produce it. f should be a reducing +step function that accepts both 1 and 2 arguments, if it accepts only +2 you can add the arity-1 with `completing`. Returns the result of +applying (the transformed) `xform` to `init` and the first item in +`coll`, then applying `xform` to that result and the 2nd item, etc. If +`coll` contains no items, returns `init` and `f` is not called. Note +that certain transforms may inject or skip items. + +## `transient` +Function signature: + +``` +(transient [coll]) +``` + +Returns a new, transient version of the collection. + +## `tree-seq` +Function signature: + +``` +(tree-seq [branch? children root]) +``` + +Returns a lazy sequence of the nodes in a tree, via a depth-first walk. + +`branch?` must be a function of one arg that returns true if passed a +node that can have children (but may not). `children` must be a +function of one arg that returns a sequence of the children. Will +only be called on nodes for which `branch?` returns true. `root` is +the root node of the tree. + +### Examples + +For the given tree `["A" ["B" ["D"] ["E"]] ["C" ["F"]]]`: + + A + / \ + B C + / \ \ + D E F + +Calling `tree-seq` with `next` as the `branch?` and `rest` as the +`children` returns a flat representation of a tree: + +``` fennel +(assert-eq (map first (tree-seq next rest ["A" ["B" ["D"] ["E"]] ["C" ["F"]]])) + ["A" "B" "D" "E" "C" "F"]) +``` + +## `unreduced` +Function signature: + +``` +(unreduced [x]) +``` + +**Undocumented** + +## `update` +Function signature: + +``` +(update [tbl key f]) +``` + +Update table value stored under `key` by calling a function `f` on +that value. `f` must take one argument, which will be a value stored +under the key in the table. + +### Examples + +Same as `assoc` but accepts function to produce new value based on key value. + +``` fennel +(assert-eq + {:data "THIS SHOULD BE UPPERCASE"} + (update {:data "this should be uppercase"} :data string.upper)) +``` + +## `update-in` +Function signature: + +``` +(update-in [tbl key-seq f]) +``` + +Update table value stored under set of immutable nested tables, via +given `key-seq` by calling a function `f` on the value stored under the +last key. `f` must take one argument, which will be a value stored +under the key in the table. Returns a new immutable table. + +### Examples + +Same as `assoc-in` but accepts function to produce new value based on key value. + +``` fennel +(fn capitalize-words [s] + (pick-values 1 + (s:gsub "(%a)([%w_`]*)" #(.. ($1:upper) ($2:lower))))) + +(assert-eq + {:user {:name "John Doe"}} + (update-in {:user {:name "john doe"}} [:user :name] capitalize-words)) +``` + +## `vec` +Function signature: + +``` +(vec [coll]) +``` + +Coerce collection `coll` to a vector. + +## `zipmap` +Function signature: + +``` +(zipmap [keys vals]) +``` + +Return an associative table with the `keys` mapped to the +corresponding `vals`. + + +--- + +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 --> diff --git a/doc/macros.md b/doc/macros.md index c90d0af..bac17f9 100644 --- a/doc/macros.md +++ b/doc/macros.md @@ -1,310 +1,44 @@ -# Macros (v0.5.4) -Macros for Cljlib that implement various facilities from Clojure. +# Macros (v1.0.0) +Macros for fennel-cljlib. **Table of contents** -- [`fn*`, `defn`](#fn-defn) -- [`try`](#try) +- [`cond`](#cond) - [`def`](#def) -- [`defonce`](#defonce) -- [`defmulti`](#defmulti) - [`defmethod`](#defmethod) -- [`into`](#into) -- [`empty`](#empty) -- [`with-meta`](#with-meta) -- [`meta`](#meta) +- [`defmulti`](#defmulti) +- [`defn`](#defn) +- [`defn-`](#defn-) +- [`fn*`](#fn) - [`if-let`](#if-let) -- [`when-let`](#when-let) - [`if-some`](#if-some) -- [`when-some`](#when-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) -## `fn*`, `defn` -Function signature: - -``` -(fn* name docstring? ([arglist*] body)*) -``` - -Create (anonymous) function of fixed arity. -Accepts optional `name` and `docstring?` as first two arguments, -followed by single or multiple arity bodies defined as lists. Each -list starts with `arglist*` vector, which supports destructuring, and -is followed by `body*` wrapped in implicit `do`. - -### Examples -Named function of fixed arity 2: - -``` fennel -(fn* f [a b] (+ a b)) -``` - -Function of fixed arities 1 and 2: - -``` fennel -(fn* ([x] x) - ([x y] (+ x y))) -``` - -Named function of 2 arities, one of which accepts 0 arguments, and the -other one or more arguments: - -``` fennel -(fn* f - ([] nil) - ([x & xs] - (print x) - (f ((or table.unpack _G.unpack) xs)))) -``` - -Note, that this function is recursive, and calls itself with less and -less amount of arguments until there's no arguments, and terminates -when the zero-arity body is called. - -Named functions accept additional documentation string before the -argument list: - -``` fennel -(fn* cube - "raise `x` to power of 3" - [x] - (^ x 3)) - -(fn* greet - "greet a `person`, optionally specifying default `greeting`." - ([person] (print (.. "Hello, " person "!"))) - ([greeting person] (print (.. greeting ", " person "!")))) -``` - -Argument lists follow the same destruction rules as per `let`. -Variadic arguments with `...` are not supported use `& rest` instead. -Note that only one arity with `&` is supported. - -##### Namespaces -If function name contains namespace part, defines local variable -without namespace part, then creates function with this name, sets -this function to the namespace, and returns it. - -This roughly means, that instead of writing this: - -``` fennel -(local ns {}) - -(fn f [x] ;; we have to define `f` without `ns` - (if (> x 0) (f (- x 1)))) ;; because we're going to use it in `g` - -(set ns.f f) - -(fn ns.g [x] (f (* x 100))) ;; `g` can be defined as `ns.g` as it is only exported - -ns -``` - -It is possible to write: - -``` fennel -(local ns {}) - -(fn* ns.f [x] - (if (> x 0) (f (- x 1)))) - -(fn* ns.g [x] (f (* x 100))) ;; we can use `f` here no problem - -ns -``` - -It is still possible to call `f` and `g` in current scope without `ns` -part, so functions can be reused inside the module, and `ns` will hold -both functions, so it can be exported from the module. - -Note that `fn` will not create the `ns` for you, hence this is just a -syntax sugar. Functions deeply nested in namespaces require exising -namespace tables: - -``` fennel -(local ns {:strings {} - :tables {}}) - -(fn* ns.strings.join - ([s1 s2] (.. s1 s2)) - ([s1 s2 & strings] - (join (join s1 s2) ((or table.unpack _G.unpack) strings)))) ;; call `join` resolves to ns.strings.join - -(fn* ns.tables.join - ([t1 t2] - (let [res []] - (each [_ v (ipairs t1)] (table.insert res v)) - (each [_ v (ipairs t2)] (table.insert res v)) - res)) - ([t1 t2 & tables] - (join (join t1 t2) ((or table.unpack _G.unpack) tables)))) ;; call to `join` resolves to ns.tables.join - -(assert-eq (ns.strings.join "a" "b" "c") "abc") - -(assert-eq (join ["a"] ["b"] ["c"] ["d" "e"]) - ["a" "b" "c" "d" "e"]) -(assert-eq (join "a" "b" "c") - []) -``` - -Note that this creates a collision and local `join` overrides `join` -from `ns.strings`, so the latter must be fully qualified -`ns.strings.join` when called outside of the function. - -## `try` +## `cond` 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`. - -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) +(cond ...) ``` +**Undocumented** ## `def` Function signature: ``` -(def attr-map? name expr) -``` - -Wrapper around `local` which can declare variables inside namespace, -and as local `name` at the same time similarly to -[`fn*`](#fn). Accepts optional `attr-map?` which can contain a -docstring, and whether variable should be mutable or not. Sets -variable to the result of `expr`. - -``` fennel -(def ns {}) -(def a 10) ;; binds `a` to `10` - -(assert-eq a 10) - -(def ns.b 20) ;; binds `ns.b` and `b` to `20` - -(assert-eq b 20) -(assert-eq ns.b 20) -``` - -`a` is a `local`, and both `ns.b` and `b` refer to the same value. - -Additionally metadata can be attached to values, by providing -attribute map or keyword as first parameter. Only one keyword is -supported, which is `:mutable`, which allows mutating variable with -`set` later on: - -``` fennel -;; Bad, will override existing documentation for 299792458 (if any) -(def {:doc "speed of light in m/s"} c 299792458) - -(def :mutable address "Lua St.") ;; same as (def {:mutable true} address "Lua St.") -(set address "Lisp St.") ;; can mutate `address` -``` - -However, attaching documentation metadata to anything other than -tables and functions considered bad practice, due to how Lua -works. More info can be found in [`with-meta`](#with-meta) -description. - -## `defonce` -Function signature: - -``` -(defonce attr-map? name expr) -``` - -Works the same as [`def`](#def), but ensures that later [`defonce`](#defonce) -calls will not override existing bindings. Accepts same `attr-map?` as -[`def`](#def), and sets `name` to the result of `expr`: - -``` fennel -(defonce a 10) -(defonce a 20) -(assert-eq a 10) -``` - -## `defmulti` -Function signature: - -``` -(defmulti name docstring? dispatch-fn options*) +(def ...) ``` -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. +**Undocumented** ## `defmethod` Function signature: @@ -328,6 +62,8 @@ 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) @@ -343,6 +79,8 @@ were found for given dispatch value. Multi-arity function tails are also supported: ``` fennel +(ns test) + (defmulti foo (fn* ([x] [x]) ([x y] [x y]))) (defmethod foo [10] [_] (print "I've knew I'll get 10")) @@ -363,6 +101,8 @@ 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)) @@ -391,186 +131,124 @@ 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. -## `into` +## `defmulti` Function signature: ``` -(into to from) -``` - -Transform table `from` into another table `to`. Mutates first table. - -Transformation happens in runtime, but type deduction happens in -compile time if possible. This means, that if literal values passed -to [`into`](#into) this will have different effects for associative tables and -vectors: - -``` fennel -(assert-eq (into [1 2 3] [4 5 6]) [1 2 3 4 5 6]) -(assert-eq (into {:a 1 :c 2} {:a 0 :b 1}) {:a 0 :b 1 :c 2}) -``` - -Conversion between different table types is also supported: - -``` fennel -(assert-eq (into [] {:a 1}) [[:a 1]]) -(assert-eq (into {} [[:a 1] [:b 2]]) {:a 1 :b 2}) +(defmulti name docstring? dispatch-fn options*) ``` -Same rules apply to runtime detection of table type, except that this -will not work for empty tables: - -``` fennel -(local empty-table {}) -(assert-eq (into empty-table {:a 1}) [[:a 1]]) -``` fennel - -If table is empty, [`into`](#into) defaults to sequential table, because it -allows safe conversion from both sequential and associative tables. - -Type for non empty tables hidden in variables can be deduced at -runtime, and this works as expected: +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`. -``` fennel -(local t1 [1 2 3]) -(local t2 {:a 10 :c 3}) -(assert-eq (into t1 {:a 1}) [1 2 3 [:a 1]]) -(assert-eq (into t2 {:a 1}) {:a 1 :c 3}) -``` +Accepts optional `docstring?`, and `options*` arguments, where +`options*` is a sequence of key value pairs representing additional +attributes. Supported options: -`cljlib.fnl` module provides two additional functions `vector` and -`hash-map`, that can create empty tables, which can be distinguished -at runtime: +`:default` - the default dispatch value, defaults to `:default`. -``` fennel -(assert-eq (into (vector) {:a 1}) [[:a 1]]) -(assert-eq (into (hash-map) [[:a 1] [:b 2]]) {:a 1 :b 2}) -``` +By default, multifunction has no multimethods, see +[`defmethod`](#defmethod) on how to add one. -## `empty` +## `defn` Function signature: ``` -(empty x) +(defn ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +])) ``` -Return empty table of the same kind as input table `x`, with -additional metadata indicating its type. - -### Example -Creating a generic `map` function, that will work on any table type, -and return result of the same type: - -``` fennel -(fn map [f tbl] - (let [res []] - (each [_ v (ipairs (into [] tbl))] - (table.insert res (f v))) - (into (empty tbl) res))) +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. -(assert-eq (map (fn [[k v]] [(string.upper k) v]) {:a 1 :b 2 :c 3}) - {:A 1 :B 2 :C 3}) -(assert-eq (map #(* $ $) [1 2 3 4]) - [1 4 9 16]) -``` -See [`into`](#into) for more info on how conversion is done. - -## `with-meta` +## `defn-` Function signature: ``` -(with-meta value meta) +(defn- ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +])) ``` -Attach [`meta`](#meta) to a `value`. - -``` fennel -(local foo (with-meta (fn [...] (let [[x y z] [...]] (+ x y z))) - {:fnl/arglist ["x" "y" "z" "..."] - :fnl/docstring "sum first three values"})) -;; (doc foo) -;; => (foo x y z ...) -;; => sum first three values -``` +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. -## `meta` +## `fn*` Function signature: ``` -(meta value) +(fn* ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +])) ``` -Get `value` metadata. If value has no metadata returns `nil`. - -### Example +Clojure-inspired `fn` macro for defining functions. +Supports multi-arity dispatching via the following syntax: -``` fennel -(meta (with-meta {} {:meta "data"})) -;; => {:meta "data"} -``` +(fn* optional-name + optional-docstring + ([arity1] body1) + ([other arity2] body2)) -### Note -There are several important gotchas about using metadata. +Accepts pre and post conditions in a form of a table after argument +list: -First, note that this works only when used with Fennel, and only when -`(require fennel)` works. For compiled Lua library this feature is -turned off. +(fn* optional-name + optional-docstring + [arg1 arg2] + {:pre [(check1 arg1 arg2) (check2 arg1)] + :post [(check1 $) ... (checkN $)]} + body) -Second, try to avoid using metadata with anything else than tables and -functions. When storing function or table as a key into metatable, -its address is used, while when storing string of number, the value is -used. This, for example, may cause documentation collision, when -you've set some variable holding a number value to have certain -docstring, and later you've defined another variable with the same -value, but different docstring. While this isn't a major breakage, it -may confuse if someone will explore your code in the REPL with `doc`. +The same syntax applies to multi-arity version. -Lastly, note that prior to Fennel 0.7.1 `import-macros` wasn't -respecting `--metadata` switch. So if you're using Fennel < 0.7.1 -this stuff will only work if you use `require-macros` instead of -`import-macros`. +(pre and post checks are not yet implemented) ## `if-let` Function signature: ``` -(if-let [binding test] then-branch else-branch) +(if-let [name test] if-branch else-branch ...) ``` -If `binding` is set by `test` to logical true, evaluates `then-branch` -with binding-form bound to the value of test, if not, yields -`else-branch`. +**Undocumented** -## `when-let` +## `if-some` Function signature: ``` -(when-let [binding test] & body) +(if-some [name test] if-branch else-branch ...) ``` -If `binding` was bound by `test` to logical true, evaluates `body` in -implicit `do`. +**Undocumented** -## `if-some` +## `in-ns` Function signature: ``` -(if-some [binding test] then-branch else-branch) +(in-ns name) ``` -If `test` is non-`nil`, evaluates `then-branch` with `binding`-form bound -to the value of test, if not, yields `else-branch`. +**Undocumented** -## `when-some` +## `lazy-cat` Function signature: ``` -(when-some [binding test] & body) +(lazy-cat ...) ``` -If `test` sets `binding` to non-`nil`, evaluates `body` in implicit -`do`. +**Undocumented** + +## `lazy-seq` +Function signature: +``` +(lazy-seq ...) +``` + +**Undocumented** ## `loop` Function signature: @@ -581,8 +259,9 @@ Function signature: 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*`. +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. @@ -608,6 +287,112 @@ 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) +## `ns` +Function signature: + +``` +(ns name commentary requirements) +``` + +**Undocumented** + +## `time` +Function signature: + +``` +(time expr) +``` + +Measure expression execution time in ms. + +## `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`. + +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] ...) +``` + +**Undocumented** + +## `when-some` +Function signature: + +``` +(when-some [name test] ...) +``` + +**Undocumented** + --- @@ -616,5 +401,5 @@ Copyright (C) 2020-2021 Andrey Listopadov License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE) -<!-- Generated with Fenneldoc v0.1.6 +<!-- Generated with Fenneldoc v0.1.9 https://gitlab.com/andreyorst/fenneldoc --> |