summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.org133
-rw-r--r--core.fnl20
2 files changed, 145 insertions, 8 deletions
diff --git a/README.org b/README.org
index 3b5d769..dd83930 100644
--- a/README.org
+++ b/README.org
@@ -30,16 +30,16 @@ Capable of producing multi-arity functions:
([lower upper] (range lower upper 1))
([lower upper step]
(let [res []]
- (for [i lower upper step]
+ (for [i lower (- upper 1) step]
(table.insert res i))
res)))
(range 10)
- ;; [0 1 2 3 4 5 6 7 8 9 10]
+ ;; [0 1 2 3 4 5 6 7 8 9]
(range -10 0)
- ;; [-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0]
+ ;; [-10 -9 -8 -7 -6 -5 -4 -3 -2 -1]
(range 0 1 0.2)
- ;; [0.0 0.2 0.4 0.6 0.8 1.0]
+ ;; [0.0 0.2 0.4 0.6 0.8]
;; both variants support up to one arity with & more:
(fn* list [& xs] xs)
@@ -49,10 +49,125 @@ Capable of producing multi-arity functions:
#+end_src
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
+ (if-let [val (test)]
+ (print val)
+ :fail)
+#+end_src
+
+Expanded form:
+
+#+begin_src fennel
+ (let [tmp (test)]
+ (if tmp
+ (let [val tmp]
+ (print val))
+ :fail))
+#+end_src
+
+=when-let= is mostly the same, except doesn't have false branch and accepts any amount of forms:
+
+#+begin_src fennel
+ (when-let [val (test)]
+ (print val)
+ val)
+#+end_src
+
+Expanded form:
+
+#+begin_src fennel
+ (let [tmp (test)]
+ (if tmp
+ (let [val tmp]
+ (print val)
+ val)))
+#+end_src
+
+*** =if-some= and =when-some=
+Much like =if-let= and =when-let=, except tests expression for =nil=.
+
+#+begin_src fennel
+ (when-some [val (foo)]
+ (print (.. "val is not nil: " val))
+ val)
+#+end_src
+
** Functions
Here are some important functions from the library.
Full set can be examined by requiring the module.
+*** =seq= and =into=
+=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:
+
+#+begin_src fennel
+ (seq [1 2 3 4 5])
+ ;; [1 2 3 4 5]
+
+ (seq {:a 1 :b 2 :c 3 :d 4})
+ ;; [["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.
+
+*** =first= and =rest=
+=first= returns first value of a table.
+It call =seq= on it, so this takes linear time for any table.
+As a consequence, associative tables are supported:
+
+#+begin_src fennel
+ (first [1 2 3])
+ ;; 1
+
+ (first {:host "localhost" :port 2344 :options {}})
+ ;; ["host" "localhost"]
+#+end_src
+
+=last= works the same way, but returns everything except first argument as a table.
+It also calls =seq= on it's argument.
+
+#+begin_src fennel
+ (rest [1 2 3])
+ ;; [2 3]
+
+ (rest {:host "localhost" :port 2344 :options {}})
+ ;; [["port" 2344] ["options" {}]]
+#+end_src
+
+*** =conj= and =cons=
+Unlike Clojure, =conj=, and =cons= modify table passed to these functions.
+This is done both to avoid copying of whole thing, and because Fennel doesn't have immutability guarantees.
+Both functions return the resulting table, so it is possible to nest these, or build a classic =map=:
+
+#+begin_src fennel
+ (fn map [f col]
+ (if-some [val (first col)]
+ (cons (f val) (map f (rest col)))
+ []))
+#+end_src
+
+=cons= accepts value as its first argument and table as second and puts value to the front of the table.
+=col= is not modified by the =map= function described above, but the =[]= table in the =else= branch of =is-some= is.
+
+=conj= accepts table as it's first argument and any amount of values afterwards.
+It puts values in order given into the table:
+
+#+begin_src fennel
+ (conj [] 1 2 3)
+ ; [1 2 3]
+#+end_src
+
*** =mapv= and =mapkv=
Mapping functions.
In Clojure we have a =seq= abstraction, that allows us to use single =mapv= on both vectors, and hash tables.
@@ -94,4 +209,14 @@ Work the same as in Clojure, except doesn't yield transducer when only function
(reduce add 10 [1 2 3 4 5]) ;; 25
#+end_src
+=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
+ (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
diff --git a/core.fnl b/core.fnl
index 1c84b26..e1f3ae0 100644
--- a/core.fnl
+++ b/core.fnl
@@ -16,14 +16,26 @@ 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."
- (. itbl 1))
+ (. (seq itbl) 1))
(fn rest [itbl]
"Returns table of all elements of indexed table but the first one."
- (let [[_ & xs] itbl]
+ (let [[_ & xs] (seq itbl)]
xs))
@@ -49,7 +61,7 @@ sequential table, leaves it unchanged."
(consj itbl x))))
-(fn* cons [x itbl]
+(fn cons [x itbl]
"Insert `x' to `itbl' at the front. Modifies `itbl'."
(doto (or itbl [])
(insert 1 x)))
@@ -209,13 +221,13 @@ sorting tables first."
))
{: seq
+ : into
: mapv
: mapkv
: reduce
: reduce-kv
: conj
: cons
- : consj
: first
: rest
: eq?