diff options
| -rw-r--r-- | .fenneldoc | 12 | ||||
| -rw-r--r-- | doc/core.md | 67 | ||||
| -rw-r--r-- | doc/macros.md | 76 | ||||
| -rw-r--r-- | init-macros.fnl | 183 | ||||
| -rw-r--r-- | init.fnl | 55 |
5 files changed, 247 insertions, 146 deletions
@@ -36,7 +36,7 @@ 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: +Fennel specific, so it should work on Lua, e.g: ``` lua Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio @@ -48,13 +48,13 @@ Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio 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. +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 +special macro for creating multi-arity functions. So when you see function signature like `(foo [x])`, this means that this is function `foo', that accepts exactly one argument `x'. In contrary, functions created with `fn' will produce `(foo x)` signature (`x' is not inside diff --git a/doc/core.md b/doc/core.md index a247529..74bd2c3 100644 --- a/doc/core.md +++ b/doc/core.md @@ -4,7 +4,7 @@ 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: +Fennel specific, so it should work on Lua, e.g: ``` lua Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio @@ -16,13 +16,13 @@ Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio 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. +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 +special macro for creating multi-arity functions. So when you see function signature like `(foo [x])`, this means that this is function `foo`, that accepts exactly one argument `x`. In contrary, functions created with `fn` will produce `(foo x)` signature (`x` is not inside @@ -342,7 +342,7 @@ see `hash-map` for creating tables that have additional metadata attached for this test to work. ### Examples -Non empty map: +Non-empty map: ``` fennel (assert-is (map? {:a 1 :b 2})) @@ -367,9 +367,9 @@ Function signature: (vector? [x]) ``` -Check whether `tbl` is an sequential table. +Check whether `tbl` is a sequential table. -Non empty sequential tables are tested for two things: +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`. @@ -379,7 +379,7 @@ see `vector` for creating tables that have additional metadata attached for this test to work. ### Examples -Non empty vector: +Non-empty vector: ``` fennel (assert-is (vector? [1 2 3 4])) @@ -571,7 +571,7 @@ Function signature: (vector [& args]) ``` -Constructs sequential table out of it's arguments. +Constructs sequential table out of its arguments. Sets additional metadata for function `vector?` to work. @@ -589,10 +589,10 @@ 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. +Construct a sequence 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: @@ -602,7 +602,7 @@ Sequential tables are transformed to sequences: ``` Associative tables are transformed to format like this `[[key1 value1] -... [keyN valueN]]` and order is non deterministic: +... [keyN valueN]]` and order is non-deterministic: ``` fennel (seq {:a 1 :b 2 :c 3}) ;; @seq([:b 2] [:a 1] [:c 3]) @@ -800,7 +800,7 @@ Reduces an associative table using function `f` and initial value `val`. 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 +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` @@ -841,9 +841,9 @@ Function signature: 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. +of second items in each coll, until any one of the `colls` is +exhausted. Any remaining items in other collections are ignored. +Function `f` should accept number-of-colls arguments. ## `filter` Function signature: @@ -890,7 +890,8 @@ Function signature: (range ([]) ([upper]) ([lower upper]) ([lower upper step])) ``` -Returns lazy sequence of of numbers from `lower` to `upper` with optional `step`. +Returns lazy sequence of numbers from `lower` to `upper` with optional +`step`. ## `reverse` Function signature: @@ -899,7 +900,7 @@ Function signature: (reverse [coll]) ``` -Returns a lazy sequnce with same items as in `coll` but in reverse order. +Returns a lazy sequence with same items as in `coll` but in reverse order. ## `take` Function signature: @@ -940,7 +941,7 @@ 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 +partition up to `n` items. In case there are not enough padding elements, return a partition with less than `n` items. ## `identity` @@ -970,7 +971,7 @@ Function signature: 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. +opposite truth value. ## `constantly` Function signature: @@ -1069,7 +1070,8 @@ Function signature: (find [coll key]) ``` -Returns the map entry for `key`, or `nil` if key not present in `coll`. +Returns the map entry for `key`, or `nil` if key is not present in +`coll`. ## `dissoc` Function signature: @@ -1096,7 +1098,7 @@ Function signature: (remove-all-methods [multimethod]) ``` -Removes all of the methods of `multimethod` +Removes all methods of `multimethod` ## `methods` Function signature: @@ -1213,7 +1215,8 @@ Function signature: (contains? [coll elt]) ``` -Test if `elt` is in the `coll`. May be a linear search depending on the type of the collection. +Test if `elt` is in the `coll`. It may be a linear search depending +on the type of the collection. ## `count` Function signature: @@ -1511,7 +1514,7 @@ Function signature: 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 +`f` must be free of side effects. Returns a transducer when no collection is provided. ## `lazy-seq` @@ -1548,8 +1551,8 @@ 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 + ;; this will error because only first line was realized, but the + ;; file was closed before the rest of lines were cached (assert-not (pcall next lines))) ``` @@ -1634,7 +1637,7 @@ Function signature: 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 +second item in `coll`, etc., until `coll` is exhausted. Returns a transducer when no collection is provided. ## `mapcat` @@ -1954,7 +1957,7 @@ Function signature: ``` `reduce` with a transformation of `f` (`xform`). If `init` is not -supplied, `f` will be called to produce it. f should be a reducing +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 diff --git a/doc/macros.md b/doc/macros.md index d757495..8021db9 100644 --- a/doc/macros.md +++ b/doc/macros.md @@ -46,7 +46,7 @@ namespace set with the `ns` macro, unless `:private` was passed before the binding name. Accepts the `name` to be bound and the `initializer` expression. `meta` can be either an associative table where keys are strings, or a string representing a key from the table. If a sole -string is given, it's value is set to `true` in the meta table. +string is given, its value is set to `true` in the meta table. ## `defmethod` Function signature: @@ -55,7 +55,7 @@ Function signature: (defmethod multi-fn dispatch-value fnspec) ``` -Attach new method to multi-function dispatch value. accepts the +Attach new method to multi-function dispatch value. Accepts the `multi-fn` as its first argument, the `dispatch-value` as second, and `fnspec` - a function tail starting from argument list, followed by function body as in [`fn*`](#fn). @@ -91,14 +91,14 @@ Multi-arity function tails are also supported: (defmulti foo (fn* ([x] [x]) ([x y] [x y]))) -(defmethod foo [10] [_] (print "I've knew I'll get 10")) -(defmethod foo [10 20] [_ _] (print "I've knew I'll get both 10 and 20")) +(defmethod foo [10] [_] (print "I knew I'll get 10")) +(defmethod foo [10 20] [_ _] (print "I knew I'll get both 10 and 20")) (defmethod foo :default ([x] (print (.. "Umm, got" x))) ([x y] (print (.. "Umm, got both " x " and " y)))) ``` -Calling `(foo 10)` will print `"I've knew I'll get 10"`, and calling -`(foo 10 20)` will print `"I've knew I'll get both 10 and 20"`. +Calling `(foo 10)` will print `"I knew I'll get 10"`, and calling +`(foo 10 20)` will print `"I knew I'll get both 10 and 20"`. However, calling `foo` with any other numbers will default either to `"Umm, got x"` message, when called with single value, and `"Umm, got both x and y"` when calling with two values. @@ -168,10 +168,10 @@ Function signature: (defn ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +])) ``` -Same as (def name (fn* name docstring? [params*] pre-post? exprs*)) -or (def name (fn* name docstring? ([params*] pre-post? exprs*)+)) with -any doc-string or attrs added to the function metadata. Accepts -`name` wich will be used to refer to a function in the current +Same as `(def name (fn* name docstring? [params*] pre-post? exprs*))` +or `(def name (fn* name docstring? ([params*] pre-post? exprs*)+))` +with any doc-string or attrs added to the function metadata. Accepts +`name` which will be used to refer to a function in the current namespace, and optional `doc-string?`, a vector of function's `params*`, `pre-post?` conditions, and the `body` of the function. The body is wrapped in an implicit do. See `fn*` for more info. @@ -183,13 +183,13 @@ Function signature: (defn- ([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body) +])) ``` -Same as (def :private name (fn* name docstring? [params*] pre-post? -exprs*)) or (def :private name (fn* name docstring? ([params*] -pre-post? exprs*)+)) with any doc-string or attrs added to the -function metadata. Accepts `name` wich will be used to refer to a -function, and optional `doc-string?`, a vector of function's `params*`, -`pre-post?` conditions, and the `body` of the function. The body is -wrapped in an implicit do. See `fn*` for more info. +Same as `(def :private name (fn* name docstring? [params*] pre-post? +exprs*))` or `(def :private name (fn* name docstring? ([params*] +pre-post? exprs*)+))` with any doc-string or attrs added to the +function metadata. Accepts `name` which will be used to refer to a +function, and optional `doc-string?`, a vector of function's +`params*`, `pre-post?` conditions, and the `body` of the function. +The body is wrapped in an implicit do. See `fn*` for more info. ## `fn*` Function signature: @@ -222,7 +222,7 @@ list: The same syntax applies to multi-arity version. -(pre and post checks are not yet implemented) +(pre- and post-checks are not yet implemented) ## `if-let` Function signature: @@ -232,7 +232,7 @@ Function signature: ``` When `test` is logical `true`, evaluates the `if-branch` with `name` -bound to the value of `test`. Otherwise evaluates the `else-branch` +bound to the value of `test`. Otherwise, evaluates the `else-branch` ## `if-some` Function signature: @@ -242,7 +242,7 @@ Function signature: ``` When `test` is not `nil`, evaluates the `if-branch` with `name` -bound to the value of `test`. Otherwise evaluates the `else-branch` +bound to the value of `test`. Otherwise, evaluates the `else-branch` ## `in-ns` Function signature: @@ -251,11 +251,12 @@ Function signature: (in-ns name) ``` -Sets the compile time variable `current-ns` to the given `name`. +Sets the compile-time variable `cljlib-namespaces` to the given `name`. Affects such macros as `def`, `defn`, which will bind names to the specified namespace. ### Examples +Creating several namespaces in the file, and defining functions in each: ```fennel (ns a) @@ -273,6 +274,33 @@ specified namespace. (assert-eq (b.g) "g from b") ``` +Note, switching namespaces in the REPL doesn't affect non-namespaced +local bindings. In other words, when defining a local with `def`, a +bot a local binding and a namespaced binding are created, and +switching current namespace won't change the local binding: + +``` +>> (ns foo) +nil +>> (def x 42) +nil +>> (ns bar) +nil +>> (def x 1337) +nil +>> (in-ns foo) +#<namespace: foo> +>> x ; user might have expected to see 42 here +1337 +>> foo.x +42 +>> bar.x +1337 +``` + +Sadly, Fennel itself has no support for namespace switching in REPL, +so this feature can be only partially emulated by the cljlib library. + ## `lazy-cat` Function signature: @@ -291,7 +319,7 @@ Function signature: (lazy-seq & body) ``` -Takes a `body` of expressions that returns an sequence, table or nil, +Takes a `body` of expressions that returns a sequence, table or nil, and yields a lazy sequence that will invoke the body only the first time `seq` is called, and will cache the result and return it on all subsequent `seq` calls. See also - `realized?` @@ -374,6 +402,8 @@ Note that when no `:as` alias is given, the library will be named after the innermost part of the require path, i.e. `some.lib` is transformed to `lib`. +See `in-ns` on how to switch namespaces. + ## `time` Function signature: @@ -401,7 +431,7 @@ 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 +The `finally` clause is optional, and written as (finally body*). If present, it must be the last clause in the [`try`](#try) form, and the only `finally` clause. Note that `finally` clause is for side effects only, and runs either after succesful run of [`try`](#try) body, or after any diff --git a/init-macros.fnl b/init-macros.fnl index 034b9aa..0e45c77 100644 --- a/init-macros.fnl +++ b/init-macros.fnl @@ -29,10 +29,6 @@ SOFTWARE.") (fn string? [x] (= :string (type x))) -;;; ns - -(var current-ns nil) - (fn has? [tbl sym] ;; searches for the given symbol in a table. (var has false) @@ -40,6 +36,97 @@ SOFTWARE.") (set has (= sym elt))) has) +;;; ns + +(local cljlib-namespaces + {} + ;; A map of files and their respective namespaces. Each entry is a + ;; filename followed by a table with two keys: `:current` and + ;; `:known`. The second one holds all namespaces that were defined + ;; for the file via the `ns` macro, and thus are available to switch + ;; with the `in-ns` macro. The `:current` key represents currently + ;; active namespace that is used for binding via the `def` macro and + ;; its derivatives. + ) + +(fn current-file [ast] + (. (ast-source ast) :filename)) + +(fn create-ns [name] + (let [file (current-file name)] + (when (not (. cljlib-namespaces file)) + (tset cljlib-namespaces file {:known {}})) + (tset cljlib-namespaces file :current name) + (tset cljlib-namespaces file :known (tostring name) true)) + `(setmetatable + {} + {:__name "namespace" + :__fennelview #(do ,(: "#<namespace: %s>" :format (tostring name)))})) + +(fn known-ns? [name] + (let [file (current-file name)] + (?. cljlib-namespaces file :known (tostring name)))) + +(fn current-ns [ast] + (?. cljlib-namespaces (current-file ast) :current)) + +(fn in-ns [name] + "Sets the compile-time variable `cljlib-namespaces` to the given `name`. +Affects such macros as `def`, `defn`, which will bind names to the +specified namespace. + +# Examples +Creating several namespaces in the file, and defining functions in each: + +```fennel +(ns a) +(defn f [] \"f from a\") +(ns b) +(defn f [] \"f from b\") +(in-ns a) +(defn g [] \"g from a\") +(in-ns b) +(defn g [] \"g from b\") + +(assert-eq (a.f) \"f from a\") +(assert-eq (b.f) \"f from b\") +(assert-eq (a.g) \"g from a\") +(assert-eq (b.g) \"g from b\") +``` + +Note, switching namespaces in the REPL doesn't affect non-namespaced +local bindings. In other words, when defining a local with `def`, a +bot a local binding and a namespaced binding are created, and +switching current namespace won't change the local binding: + +``` +>> (ns foo) +nil +>> (def x 42) +nil +>> (ns bar) +nil +>> (def x 1337) +nil +>> (in-ns foo) +#<namespace: foo> +>> x ; user might have expected to see 42 here +1337 +>> foo.x +42 +>> bar.x +1337 +``` + +Sadly, Fennel itself has no support for namespace switching in REPL, +so this feature can be only partially emulated by the cljlib library. +" + (assert-compile (known-ns? name) + (: "no such namespace: %s" :format (tostring name)) + name) + (tset cljlib-namespaces (current-file name) :current name) + name) + (fn ns [name commentary requirements] "Namespace declaration macro. Accepts the `name` of the generated namespace, and creates a local @@ -73,10 +160,11 @@ Which is equivalent to: Note that when no `:as` alias is given, the library will be named after the innermost part of the require path, i.e. `some.lib` is -transformed to `lib`." - (set current-ns name) +transformed to `lib`. + +See `in-ns` on how to switch namespaces." (let [bind-table [name] - require-table [{}] + require-table [(create-ns name)] requirements (if (string? commentary) requirements commentary)] @@ -110,30 +198,6 @@ transformed to `lib`." (values ,require-table (comment ,commentary))) `(local ,bind-table ,require-table)))) -(fn in-ns [name] - "Sets the compile time variable `current-ns` to the given `name`. -Affects such macros as `def`, `defn`, which will bind names to the -specified namespace. - -# Examples - -```fennel -(ns a) -(defn f [] \"f from a\") -(ns b) -(defn f [] \"f from b\") -(in-ns a) -(defn g [] \"g from a\") -(in-ns b) -(defn g [] \"g from b\") - -(assert-eq (a.f) \"f from a\") -(assert-eq (b.f) \"f from b\") -(assert-eq (a.g) \"g from a\") -(assert-eq (b.g) \"g from b\") -```" - (set current-ns name)) - ;;; def (fn def [...] @@ -142,19 +206,20 @@ namespace set with the `ns` macro, unless `:private` was passed before the binding name. Accepts the `name` to be bound and the `initializer` expression. `meta` can be either an associative table where keys are strings, or a string representing a key from the table. If a sole -string is given, it's value is set to `true` in the meta table." +string is given, its value is set to `true` in the meta table." :fnl/arglist [([name initializer]) ([meta name initializer])]} (match [...] (where (or [:private name val] [{:private true} name val])) `(local ,name ,val) [name val] - (if (in-scope? current-ns) - `(local ,name - (let [v# ,val] - (tset ,current-ns ,(tostring name) v#) - v#)) - `(local ,name ,val)))) + (let [namespace (current-ns name)] + (if (in-scope? namespace) + `(local ,name + (let [v# ,val] + (tset ,namespace ,(tostring name) v#) + v#)) + `(local ,name ,val))))) ;;; defn @@ -303,7 +368,7 @@ list: The same syntax applies to multi-arity version. -(pre and post checks are not yet implemented)" +(pre- and post-checks are not yet implemented)" :fnl/arglist [([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body)+])]} (let [{: name? : doc? : args : pre-post? : body : multi-arity?} @@ -419,10 +484,10 @@ The same syntax applies to multi-arity version. (fn defn [name ...] {:fnl/docstring - "Same as (def name (fn* name docstring? [params*] pre-post? exprs*)) -or (def name (fn* name docstring? ([params*] pre-post? exprs*)+)) with -any doc-string or attrs added to the function metadata. Accepts -`name` wich will be used to refer to a function in the current + "Same as `(def name (fn* name docstring? [params*] pre-post? exprs*))` +or `(def name (fn* name docstring? ([params*] pre-post? exprs*)+))` +with any doc-string or attrs added to the function metadata. Accepts +`name` which will be used to refer to a function in the current namespace, and optional `doc-string?`, a vector of function's `params*`, `pre-post?` conditions, and the `body` of the function. The body is wrapped in an implicit do. See `fn*` for more info." @@ -433,13 +498,13 @@ The body is wrapped in an implicit do. See `fn*` for more info." (fn defn- [name ...] {:fnl/docstring - "Same as (def :private name (fn* name docstring? [params*] pre-post? -exprs*)) or (def :private name (fn* name docstring? ([params*] -pre-post? exprs*)+)) with any doc-string or attrs added to the -function metadata. Accepts `name` wich will be used to refer to a -function, and optional `doc-string?`, a vector of function's `params*`, -`pre-post?` conditions, and the `body` of the function. The body is -wrapped in an implicit do. See `fn*` for more info." + "Same as `(def :private name (fn* name docstring? [params*] pre-post? +exprs*))` or `(def :private name (fn* name docstring? ([params*] +pre-post? exprs*)+))` with any doc-string or attrs added to the +function metadata. Accepts `name` which will be used to refer to a +function, and optional `doc-string?`, a vector of function's +`params*`, `pre-post?` conditions, and the `body` of the function. +The body is wrapped in an implicit do. See `fn*` for more info." :fnl/arglist [([name doc-string? [params*] pre-post? body]) ([name doc-string? ([params*] pre-post? body)+])]} (assert-compile (sym? name) "expected a function name, use `fn*` for anonymous functions" name) @@ -470,7 +535,7 @@ to the value of `test`." (fn if-let [[name test] if-branch else-branch ...] {:fnl/docstring "When `test` is logical `true`, evaluates the `if-branch` with `name` -bound to the value of `test`. Otherwise evaluates the `else-branch`" +bound to the value of `test`. Otherwise, evaluates the `else-branch`" :fnl/arglist [[name test] if-branch else-branch]} (assert-compile (= 0 (select "#" ...)) "too many arguments to if-let" ...) `(let [val# ,test] @@ -490,7 +555,7 @@ the value of `test`." (fn if-some [[name test] if-branch else-branch ...] {:fnl/docstring "When `test` is not `nil`, evaluates the `if-branch` with `name` -bound to the value of `test`. Otherwise evaluates the `else-branch`" +bound to the value of `test`. Otherwise, evaluates the `else-branch`" :fnl/arglist [[name test] if-branch else-branch]} (assert-compile (= 0 (select "#" ...)) "too many arguments to if-some" ...) `(let [val# ,test] @@ -561,7 +626,7 @@ By default, multifunction has no multimethods, see (fn defmethod [multifn dispatch-val ...] {:fnl/arglist [multi-fn dispatch-value fnspec] - :fnl/docstring "Attach new method to multi-function dispatch value. accepts the + :fnl/docstring "Attach new method to multi-function dispatch value. Accepts the `multi-fn' as its first argument, the `dispatch-value' as second, and `fnspec' - a function tail starting from argument list, followed by function body as in `fn*'. @@ -597,14 +662,14 @@ Multi-arity function tails are also supported: (defmulti foo (fn* ([x] [x]) ([x y] [x y]))) -(defmethod foo [10] [_] (print \"I've knew I'll get 10\")) -(defmethod foo [10 20] [_ _] (print \"I've knew I'll get both 10 and 20\")) +(defmethod foo [10] [_] (print \"I knew I'll get 10\")) +(defmethod foo [10 20] [_ _] (print \"I knew I'll get both 10 and 20\")) (defmethod foo :default ([x] (print (.. \"Umm, got\" x))) ([x y] (print (.. \"Umm, got both \" x \" and \" y)))) ``` -Calling `(foo 10)` will print `\"I've knew I'll get 10\"`, and calling -`(foo 10 20)` will print `\"I've knew I'll get both 10 and 20\"`. +Calling `(foo 10)` will print `\"I knew I'll get 10\"`, and calling +`(foo 10 20)` will print `\"I knew I'll get both 10 and 20\"`. However, calling `foo' with any other numbers will default either to `\"Umm, got x\"` message, when called with single value, and `\"Umm, got both x and y\"` when calling with two values. @@ -870,7 +935,7 @@ 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 +The `finally` clause is optional, and written as (finally body*). If present, it must be the last clause in the `try' form, and the only `finally' clause. Note that `finally' clause is for side effects only, and runs either after succesful run of `try' body, or after any @@ -957,7 +1022,7 @@ the other tests or exprs. `(cond)` returns nil." "lazy-seq.init-macros"))) (fn lazy-seq [...] - {:fnl/docstring "Takes a `body` of expressions that returns an sequence, table or nil, + {:fnl/docstring "Takes a `body` of expressions that returns a sequence, table or nil, and yields a lazy sequence that will invoke the body only the first time `seq` is called, and will cache the result and return it on all subsequent `seq` calls. See also - `realized?`" @@ -187,7 +187,7 @@ Applying `add` to different amount of arguments: (defn complement "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." +opposite truth value." [f] (fn* ([] (not (f))) @@ -415,7 +415,7 @@ see `hash-map` for creating tables that have additional metadata attached for this test to work. # Examples -Non empty map: +Non-empty map: ``` fennel (assert-is (map? {:a 1 :b 2})) @@ -445,9 +445,9 @@ Empty tables created with `hash-map` will pass the test: false)) (defn vector? - "Check whether `tbl` is an sequential table. + "Check whether `tbl` is a sequential table. -Non empty sequential tables are tested for two things: +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`. @@ -457,7 +457,7 @@ see `vector` for creating tables that have additional metadata attached for this test to work. # Examples -Non empty vector: +Non-empty vector: ``` fennel (assert-is (vector? [1 2 3 4])) @@ -592,7 +592,7 @@ Empty tables created with `vector` will pass the test: (vec* len))))) (defn vector - "Constructs sequential table out of it's arguments. + "Constructs sequential table out of its arguments. Sets additional metadata for function `vector?` to work. @@ -645,10 +645,10 @@ of bounds, `nth` raises an error unless `not-found` is supplied. x) (defn seq - "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. + "Construct a sequence 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: @@ -658,7 +658,7 @@ Sequential tables are transformed to sequences: ``` Associative tables are transformed to format like this `[[key1 value1] -... [keyN valueN]]` and order is non deterministic: +... [keyN valueN]]` and order is non-deterministic: ``` fennel (seq {:a 1 :b 2 :c 3}) ;; @seq([:b 2] [:a 1] [:c 3]) @@ -808,9 +808,9 @@ no collection is provided. (defn mapv "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." +of second items in each coll, until any one of the `colls` is +exhausted. Any remaining items in other collections are ignored. +Function `f` should accept number-of-colls arguments." ([f coll] (->> coll (core.transduce (map f) @@ -822,7 +822,7 @@ accept number-of-colls arguments." (defn map-indexed "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 +second item in `coll`, etc., until `coll` is exhausted. Returns a transducer when no collection is provided." ([f] (fn* [rf] @@ -883,7 +883,8 @@ is provided." (some #(not (pred $)) coll)) (defn range - "Returns lazy sequence of of numbers from `lower` to `upper` with optional `step`." + "Returns lazy sequence of numbers from `lower` to `upper` with optional +`step`." ([] (seq* (lazy.range))) ([upper] (seq* (lazy.range upper))) ([lower upper] (seq* (lazy.range lower upper))) @@ -895,7 +896,7 @@ is provided." (seq* (apply lazy.concat colls))) (defn reverse - "Returns a lazy sequnce with same items as in `coll` but in reverse order." + "Returns a lazy sequence with same items as in `coll` but in reverse order." [coll] (seq* (lazy.reverse coll))) @@ -1052,7 +1053,7 @@ provided." (defn keep-indexed "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 +`f` must be free of side effects. Returns a transducer when no collection is provided." ([f] (fn* [rf] @@ -1074,7 +1075,7 @@ collection is provided." 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 +partition up to `n` items. In case there are not enough padding elements, return a partition with less than `n` items." ([n coll] (map seq* (lazy.partition n coll))) ([n step coll] (map seq* (lazy.partition n step coll))) @@ -1164,7 +1165,8 @@ per reduce) of `coll` by `f`, starting with `init`." ([f init coll] (seq* (lazy.reductions f init coll)))) (defn contains? - "Test if `elt` is in the `coll`. May be a linear search depending on the type of the collection." + "Test if `elt` is in the `coll`. It may be a linear search depending +on the type of the collection." [coll elt] (lazy.contains? coll elt)) @@ -1246,8 +1248,8 @@ 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 + ;; this will error because only first line was realized, but the + ;; file was closed before the rest of lines were cached (assert-not (pcall next lines))) ``` @@ -1414,7 +1416,8 @@ unaffected." (lazy.vals coll))) (defn find - "Returns the map entry for `key`, or `nil` if key not present in `coll`." + "Returns the map entry for `key`, or `nil` if key is not present in +`coll`." [coll key] (assert (or (map? coll) (empty? coll)) "expected a map") (match (. coll key) @@ -1528,7 +1531,7 @@ called. Early termination is supported via `reduced`. 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 +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` @@ -1577,7 +1580,7 @@ suitable for transduce by adding an arity-1 signature that calls (defn transduce "`reduce` with a transformation of `f` (`xform`). If `init` is not -supplied, `f` will be called to produce it. f should be a reducing +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 @@ -2212,7 +2215,7 @@ from `macros.fnl'." multimethod) (defn remove-all-methods - "Removes all of the methods of `multimethod'" + "Removes all methods of `multimethod'" [multimethod] (if (multifn? multimethod) (each [k _ (pairs multimethod)] |