diff options
| author | Andrey Orst <andreyorst@gmail.com> | 2020-10-24 16:58:48 +0300 |
|---|---|---|
| committer | Andrey Orst <andreyorst@gmail.com> | 2020-10-24 16:58:48 +0300 |
| commit | a71664478ed365293e99a51e212e813097da58f9 (patch) | |
| tree | 7389c93b1335cf94119e9cb01c9bbd3a19d3fcf0 | |
| parent | c1e418b225d4e8f8c99ec0b8514098951d2a1881 (diff) | |
add predicates for checking maps and seqs; add COC, and update doc
| -rw-r--r-- | CODE_OF_CONDUCT.org | 5 | ||||
| -rw-r--r-- | README.org | 49 | ||||
| -rw-r--r-- | core.fnl | 25 | ||||
| -rw-r--r-- | core_test.fnl | 14 |
4 files changed, 61 insertions, 32 deletions
diff --git a/CODE_OF_CONDUCT.org b/CODE_OF_CONDUCT.org new file mode 100644 index 0000000..ad2e2da --- /dev/null +++ b/CODE_OF_CONDUCT.org @@ -0,0 +1,5 @@ +Only *code quality* does matter. + +Everything else is up to your personal taste. + +However, this doesn't mean that we will be tolerant to /any/ kind of antics. @@ -15,7 +15,7 @@ Clojure's =fn= equivalent. Returns a function of fixed arity by doing runtime dispatch, based on argument amount. Capable of producing multi-arity functions: -#+begin_src fennel +#+begin_src clojure (fn* square "square number" [x] (^ x 2)) (square 9) ;; 81.0 @@ -43,8 +43,7 @@ Capable of producing multi-arity functions: Both variants support up to one arity with =& more=: -#+begin_src fennel - +#+begin_src clojure (fn* vec [& xs] xs) (vec 1 2 3) @@ -56,7 +55,7 @@ See =core.fnl= for more examples. *** =if-let= and =when-let= When test expression is not =nil= or =false=, evaluates the first body form with the =name= bound to the result of the expressions. -#+begin_src fennel +#+begin_src clojure (if-let [val (test)] (print val) :fail) @@ -64,7 +63,7 @@ When test expression is not =nil= or =false=, evaluates the first body form with Expanded form: -#+begin_src fennel +#+begin_src clojure (let [tmp (test)] (if tmp (let [val tmp] @@ -74,7 +73,7 @@ Expanded form: =when-let= is mostly the same, except doesn't have false branch and accepts any amount of forms: -#+begin_src fennel +#+begin_src clojure (when-let [val (test)] (print val) val) @@ -82,7 +81,7 @@ Expanded form: Expanded form: -#+begin_src fennel +#+begin_src clojure (let [tmp (test)] (if tmp (let [val tmp] @@ -93,7 +92,7 @@ Expanded form: *** =if-some= and =when-some= Much like =if-let= and =when-let=, except tests expression for =nil=. -#+begin_src fennel +#+begin_src clojure (when-some [val (foo)] (print (.. "val is not nil: " val)) val) @@ -103,7 +102,7 @@ Much like =if-let= and =when-let=, except tests expression for =nil=. 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 +#+begin_src clojure (into [1 2 3] [4 5 6]) ;; [1 2 3 4 5 6] @@ -118,10 +117,10 @@ However we can do this at compile time. #+end_src Because the type check at compile time it will only respect the type when literal representation is used. -If a variable holding the table, it's type checked at runtime. +If a variable holding the table, its type is checked at runtime. Empty tables default to sequential ones: -#+begin_src fennel +#+begin_src clojure (local a []) (into a {:a 1 :b 2}) ;; [["b" 2] ["a" 1]] @@ -131,9 +130,9 @@ Empty tables default to sequential ones: ;; [["b" 2] ["a" 1]] #+end_src -However, if target table is not empty, it's type can be deduced: +However, if target table is not empty, its type can be deduced: -#+begin_src fennel +#+begin_src clojure (local a {:c 3}) (into a {:a 1 :b 2}) ;; {:a 1 :b 2 :c 3} @@ -154,7 +153,7 @@ Full set can be examined by requiring the module. =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 returns sequential table or =nil=: -#+begin_src fennel +#+begin_src clojure (seq [1 2 3 4 5]) ;; [1 2 3 4 5] @@ -175,7 +174,7 @@ See =into= on how to transform such sequence back into associative table. It call =seq= on it, so this takes linear time for any kind of table. As a consequence, associative tables are supported: -#+begin_src fennel +#+begin_src clojure (first [1 2 3]) ;; 1 @@ -184,9 +183,9 @@ As a consequence, associative tables are supported: #+end_src =last= works the same way, but returns everything except first argument as a table. -It also calls =seq= on it's argument. +It also calls =seq= on its argument. -#+begin_src fennel +#+begin_src clojure (rest [1 2 3]) ;; [2 3] @@ -203,15 +202,15 @@ This is done both to avoid copying of whole thing, and because Fennel doesn't ha =cons= accepts value as its first argument and table as second, and puts value to the front of the table: -#+begin_src fennel +#+begin_src clojure (cons 1 [2 3]) ;; [1 2 3] #+end_src -=conj= accepts table as it's first argument and any amount of values afterwards. +=conj= accepts table as its first argument and any amount of values afterwards. It puts values in order given into the table: -#+begin_src fennel +#+begin_src clojure (conj [] 1 2 3) ; [1 2 3] #+end_src @@ -219,7 +218,7 @@ It puts values in order given into the table: Both functions return the resulting table, so it is possible to nest calls to both of these. As an example, here's a classic map function: -#+begin_src fennel +#+begin_src clojure (fn map [f col] (if-some [val (first col)] (cons (f val) (map f (rest col))) @@ -234,7 +233,7 @@ Mapping function over table. In Clojure we have a =seq= abstraction, that allows us to use single =mapv= on both vectors, and hash tables. In this library the =seq= function is implemented in a similar way, so you can expect =mapv= to behave similarly to Clojure: -#+begin_src fennel +#+begin_src clojure (fn cube [x] (* x x x)) (mapv cube [1 2 3]) ;; [1 8 27] @@ -259,7 +258,7 @@ In this library the =seq= function is implemented in a similar way, so you can e Ordinary reducing functions. Work the same as in Clojure, except doesn't yield transducer when only function was passed. -#+begin_src fennel +#+begin_src clojure (fn add [a b] (+ a b)) (reduce add [1 2 3 4 5]) ;; 15 @@ -270,11 +269,11 @@ Work the same as in Clojure, except doesn't yield transducer when only function =reduce-kv= expects function that accepts 3 arguments and initial value. Then it maps function over the associative map, by passing initial value as a first argument, key as second argument, and value as third argument. -#+begin_src fennel +#+begin_src clojure (reduce-kv (fn [acc key val] (if (or (= key :a) (= key :c)) (+ acc val) acc)) 0 {:a 10 :b -20 :c 10}) ;; 20 #+end_src -# LocalWords: Luajit VM arity runtime multi Cljlib fn +# LocalWords: Luajit VM arity runtime multi Cljlib fn mapv kv @@ -14,7 +14,7 @@ If `tbl' is sequential table, leaves it unchanged." (let [res []] (each [k v (pairs tbl)] (if (and (not assoc?) - (not (= (type k) "number"))) + (not (= (type k) :number))) (set assoc? true)) (insert res [k v])) (if assoc? res tbl)))) @@ -27,13 +27,24 @@ If `tbl' is sequential table, leaves it unchanged." (when-some [tbl tbl] (. (seq tbl) 1))) - (fn rest [tbl] "Returns table of all elements of indexed table but the first one." (if-some [tbl tbl] [(_unpack (seq tbl) 2)] [])) +(fn map? [tbl] + "Check whether tbl is an associative table." + (if (= (type tbl) :table) + (let [(k _) (next tbl)] + (and (~= k nil) (or (~= (type k) :number) + (~= k 1)))))) + +(fn seq? [tbl] + "Check whether tbl is an sequential table." + (if (= (type tbl) :table) + (let [(k _) (next tbl)] + (and (~= k nil) (= (type k) :number) (= k 1))))) (fn* conj "Insert `x' as a last element of indexed table `tbl'. Modifies `tbl'" @@ -46,7 +57,6 @@ If `tbl' is sequential table, leaves it unchanged." (let [[y & xs] xs] (conj (conj tbl x) y (_unpack xs))) (conj tbl x)))) - (fn* consj "Like conj but joins at the front. Modifies `tbl'." ([] []) @@ -58,14 +68,12 @@ If `tbl' is sequential table, leaves it unchanged." (let [[y & xs] xs] (consj (consj tbl x) y (_unpack xs))) (consj tbl x)))) - (fn cons [x tbl] "Insert `x' to `tbl' at the front. Modifies `tbl'." (when-some [x x] (doto (or tbl []) (insert 1 x)))) - (fn* reduce "Reduce indexed table using function `f' and optional initial value `val'. @@ -185,7 +193,7 @@ ignored. Returns a table of results." "Deep compare values." ([x] true) ([x y] - (if (and (= (type x) "table") (= (type y) "table")) + (if (and (= (type x) :table) (= (type y) :table)) (and (reduce #(and $1 $2) true (mapv (fn [[k v]] (eq? (. y k) v)) (kvseq x))) (reduce #(and $1 $2) true (mapv (fn [[k v]] (eq? (. x k) v)) (kvseq y)))) (= x y))) @@ -220,6 +228,9 @@ ignored. Returns a table of results." (local not-any? (comp #(not $) some)) +(fn complement [f] + #(not (partial f))) + (fn* range "return range of of numbers from `lower' to `upper' with optional `step'." ([upper] (range 0 upper 1)) @@ -246,6 +257,8 @@ ignored. Returns a table of results." : cons : first : rest + : map? + : seq? : eq? : identity : comp diff --git a/core_test.fnl b/core_test.fnl index fe2a71c..d0fbb1f 100644 --- a/core_test.fnl +++ b/core_test.fnl @@ -11,6 +11,8 @@ : cons : first : rest + : map? + : seq? : eq? : identity : comp @@ -66,6 +68,13 @@ ;; different. (assert-eq {4 1} [nil nil nil 1])) +(test seq-test + (assert-eq (seq []) nil) + (assert-eq (seq {}) nil) + (assert-eq (seq [1]) [1]) + (assert-eq (seq [1 2 3]) [1 2 3]) + (assert-eq (seq {:a 1}) [["a" 1]])) + (test mapv-test (assert-eq (mapv #(* $ $) [1 2 3 4]) [1 4 9 16]) @@ -97,6 +106,7 @@ (each [_ v (ipairs c)] (set res (+ res v))) res)) + (assert-eq (reduce ++ (range 10)) 45) (assert-eq (reduce ++ -3 (range 10)) 42) (assert-eq (reduce ++ 10 nil) 10) @@ -116,4 +126,6 @@ (test filter-test (assert-eq (filter even? (range 10)) [0 2 4 6 8]) - (assert-eq (filter odd? (range 10)) [1 3 5 7 9])) + (assert-eq (filter odd? (range 10)) [1 3 5 7 9]) + (assert-eq (filter map? [{:a 1} {5 1} [1 2] [] {}]) [{:a 1} {5 1}]) + (assert-eq (filter seq? [{:a 1} {5 1} [1 2] [] {}]) [[1 2]])) |