summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODE_OF_CONDUCT.org5
-rw-r--r--README.org49
-rw-r--r--core.fnl25
-rw-r--r--core_test.fnl14
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.
diff --git a/README.org b/README.org
index 5a23b66..eb21563 100644
--- a/README.org
+++ b/README.org
@@ -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
diff --git a/core.fnl b/core.fnl
index 778f2c6..509b410 100644
--- a/core.fnl
+++ b/core.fnl
@@ -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]]))