diff options
| -rw-r--r-- | README.org | 31 | ||||
| -rw-r--r-- | core.fnl | 13 | ||||
| -rw-r--r-- | macros/core.fnl | 50 |
3 files changed, 69 insertions, 25 deletions
@@ -95,13 +95,30 @@ Much like =if-let= and =when-let=, except tests expression for =nil=. val) #+end_src +*** =into= +Clojure's =into= function implemented as macro, because Fennel has no runtime distinction between =[]= and ={}= tables, since Lua also doesn't feature this feature. +However we can do this at compile time. + +#+begin_src fennel + (into [1 2 3] [4 5 6]) + ;; [1 2 3 4 5 6] + + (into [] {:a 1 :b 2 :c 3 :d 4}) + ;; [["a" 1] ["b" 2] ["c" 3] ["d" 4]] + + (into {} [[:a 1] [:b 2] [:c 3] [:d 4]]) + ;; {:a 1 :b 2 :c 3 :d 4} + + (into {:a 0 :e 5} {:a 1 :b 2 :c 3 :d 4}) + ;; {:a 1 :b 2 :c 3 :d 4 :e 5} +#+end_src ** Functions Here are some important functions from the library. Full set can be examined by requiring the module. -*** =seq= and =into= +*** =seq= =seq= produces a sequential table from any kind of table in linear time. -Works mostly like in Clojure, but, since Fennel doesn't have list object, it always returns squential tables: +Works mostly like in Clojure, but, since Fennel doesn't have list object, it always returns sequential tables: #+begin_src fennel (seq [1 2 3 4 5]) @@ -111,15 +128,7 @@ Works mostly like in Clojure, but, since Fennel doesn't have list object, it alw ;; [["a" 1] ["b" 2] ["c" 3] ["d" 4]] #+end_src -=into= can be used to convert =seq= result back to it's original form. -Unlike clojure, =into= accepts either =:vec= or =:map= keywords: - -#+begin_src fennel - (into :map (into :vec {:a :b :c :d})) - ;; {:a "b" :c "d"} -#+end_src - -=into= uses =seq= inernally. +See [[*=into=][=into=]] on how to transform such sequence back into associative table. *** =first= and =rest= =first= returns first value of a table. @@ -16,18 +16,6 @@ sequential table, leaves it unchanged." (insert res [k v])) (if assoc? res tbl))) -(fn unseq [tbl] - (local res {}) - (each [_ [k v] (ipairs tbl)] - (tset res k v)) - res) - -(fn into [to from] - (match to - :vec (seq from) - :map (unseq from) - _ (error "unsupported table type" 2))) - (fn first [itbl] "Return first element of an indexed table." (. (seq itbl) 1)) @@ -221,7 +209,6 @@ sorting tables first." )) {: seq - : into : mapv : mapkv : reduce diff --git a/macros/core.fnl b/macros/core.fnl index e88d575..7c8af40 100644 --- a/macros/core.fnl +++ b/macros/core.fnl @@ -1,5 +1,6 @@ (import-macros {: fn*} :macros.fn) (local _unpack (or table.unpack unpack)) +(local insert table.insert) (fn check-bindings [bindings] (assert-compile (sequence? bindings) "expected binding table @@ -50,7 +51,54 @@ (let [,form tmp#] ,(_unpack body)))))) + +;; based on `seq' from `core.fnl' +(fn into [to from] + (if (sequence? to) + `(let [to# ,to + from# ,from + insert# table.insert + unpack# (or table.unpack unpack) + res# []] + (var assoc# false) + (each [k# v# (pairs from#)] + (if (and (not assoc#) + (not (= (type k#) "number"))) + (set assoc# true)) + (insert# res# [k# v#])) + (let [res# (if assoc# res# from#)] + (if (~= (next to#) nil) + (do (when (~= (next res#) nil) + (each [_# v# (ipairs res#)] + (insert# to# v#))) + to#) + res#))) + ;; to support (into {} {}) we first need transform `from' into a + ;; sequential table. Unfortunately it seems impossible to do + ;; this with `(into [] ,from)' call, as it results in infinity + ;; compilation loop. Because of that the body of previous + ;; branch is repeated here almost entirely, although without + ;; some extra checks, as these aren't necessary in this case. + (table? to) + `(let [to# ,to + from# (let [from# ,from + insert# table.insert + unpack# (or table.unpack unpack) + res# []] + (var assoc# false) + (each [k# v# (pairs from#)] + (if (and (not assoc#) + (not (= (type k#) "number"))) + (set assoc# true)) + (insert# res# [k# v#])) + (if assoc# res# from#))] + (each [_# [k# v#] (ipairs from#)] + (tset to# k# v#)) + to#) + `(error "expected table as the first argument" 2))) + {: if-let : when-let : if-some - : when-some} + : when-some + : into} |