mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 17:27:18 +00:00
Add generator expressions for easier iteration.
Similar to python generator, but with the same syntax as the loop macro.
This commit is contained in:
parent
1e87b01e02
commit
184fe31e0c
@ -25,11 +25,12 @@
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
JanetTable *t1;
|
JanetTable *t1, *t2;
|
||||||
|
|
||||||
janet_init();
|
janet_init();
|
||||||
|
|
||||||
t1 = janet_table(10);
|
t1 = janet_table(10);
|
||||||
|
t2 = janet_table(0);
|
||||||
|
|
||||||
janet_table_put(t1, janet_cstringv("hello"), janet_wrap_integer(2));
|
janet_table_put(t1, janet_cstringv("hello"), janet_wrap_integer(2));
|
||||||
janet_table_put(t1, janet_cstringv("akey"), janet_wrap_integer(5));
|
janet_table_put(t1, janet_cstringv("akey"), janet_wrap_integer(5));
|
||||||
@ -52,6 +53,14 @@ int main() {
|
|||||||
assert(janet_equals(janet_table_get(t1, janet_cstringv("hello")), janet_wrap_nil()));
|
assert(janet_equals(janet_table_get(t1, janet_cstringv("hello")), janet_wrap_nil()));
|
||||||
assert(janet_equals(janet_table_get(t1, janet_cstringv("box")), janet_wrap_nil()));
|
assert(janet_equals(janet_table_get(t1, janet_cstringv("box")), janet_wrap_nil()));
|
||||||
|
|
||||||
|
janet_table_put(t2, janet_csymbolv("t2key1"), janet_wrap_integer(10));
|
||||||
|
janet_table_put(t2, janet_csymbolv("t2key2"), janet_wrap_integer(100));
|
||||||
|
janet_table_put(t2, janet_csymbolv("some key "), janet_wrap_integer(-2));
|
||||||
|
janet_table_put(t2, janet_csymbolv("a thing"), janet_wrap_integer(10));
|
||||||
|
|
||||||
|
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10)));
|
||||||
|
assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100)));
|
||||||
|
|
||||||
janet_deinit();
|
janet_deinit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# A game of life implementation
|
# A game of life implementation
|
||||||
|
|
||||||
(def- windows
|
(def- window
|
||||||
(fora [x :range [-1 2]
|
(fora [x :range [-1 2]
|
||||||
y :range [-1 2]
|
y :range [-1 2]
|
||||||
:when (not (and (zero? x) (zero? y)))]
|
:when (not (and (zero? x) (zero? y)))]
|
||||||
@ -8,38 +8,37 @@
|
|||||||
|
|
||||||
(defn- neighbors
|
(defn- neighbors
|
||||||
[[x y]]
|
[[x y]]
|
||||||
(mapa (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) windows))
|
(mapa (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) window))
|
||||||
|
|
||||||
(defn tick
|
(defn tick
|
||||||
"Get the next state in the Game Of Life."
|
"Get the next state in the Game Of Life."
|
||||||
[state]
|
[state]
|
||||||
(def neighbor-set (frequencies (mapcat neighbors (keys state))))
|
(def cell-set (frequencies state))
|
||||||
(def next-state @{})
|
(def neighbor-set (frequencies (mapcat neighbors state)))
|
||||||
(loop [coord :keys neighbor-set
|
(fora [coord :keys neighbor-set
|
||||||
:let [count (get neighbor-set coord)]]
|
:let [count (get neighbor-set coord)]
|
||||||
(if (if (get state coord)
|
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
|
||||||
(or (= count 2) (= count 3))
|
coord))
|
||||||
(= count 3))
|
|
||||||
(put next-state coord true)))
|
|
||||||
next-state)
|
|
||||||
|
|
||||||
(defn draw
|
(defn draw
|
||||||
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
|
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
|
||||||
[state x1 y1 x2 y2]
|
[state x1 y1 x2 y2]
|
||||||
|
(def cellset @{})
|
||||||
|
(loop [cell :in state] (put cellset cell true))
|
||||||
(loop [:before (print "+" (string.repeat "--" (inc (- y2 y1))) "+")
|
(loop [:before (print "+" (string.repeat "--" (inc (- y2 y1))) "+")
|
||||||
:after (print "+" (string.repeat "--" (inc (- y2 y1))) "+")
|
:after (print "+" (string.repeat "--" (inc (- y2 y1))) "+")
|
||||||
x :range [x1 (+ 1 x2)]
|
x :range [x1 (+ 1 x2)]
|
||||||
:before (file.write stdout "|")
|
:before (file.write stdout "|")
|
||||||
:after (file.write stdout "|\n")
|
:after (file.write stdout "|\n")
|
||||||
y :range [y1 (+ 1 y2)]]
|
y :range [y1 (+ 1 y2)]]
|
||||||
(file.write stdout (if (get state (tuple x y)) "X " ". ")))
|
(file.write stdout (if (get cellset (tuple x y)) "X " ". ")))
|
||||||
(print))
|
(print))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run the example
|
# Run the example
|
||||||
#
|
#
|
||||||
|
|
||||||
(var *state* {'(0 0) true '(-1 0) true '(1 0) true '(1 1) true '(0 2) true})
|
(var *state* '[(0 0) (-1 0) (1 0) (1 1) (0 2)])
|
||||||
|
|
||||||
(loop [i :range [0 20]]
|
(loop [i :range [0 20]]
|
||||||
(print "generation " i)
|
(print "generation " i)
|
||||||
|
@ -271,7 +271,9 @@
|
|||||||
\t:range - loop over a range. The object should be two element tuple with a start
|
\t:range - loop over a range. The object should be two element tuple with a start
|
||||||
and end value. The range is half open, [start, end).\n
|
and end value. The range is half open, [start, end).\n
|
||||||
\t:keys - Iterate over the keys in a data structure.\n
|
\t:keys - Iterate over the keys in a data structure.\n
|
||||||
\t:in - Iterate over the values in an indexed data structure or byte sequence.\n\n
|
\t:in - Iterate over the values in an indexed data structure or byte sequence.\n
|
||||||
|
\t:generate - Iterate over values yielded from a fiber. Can be paired with the generator
|
||||||
|
function for the producer/consumer pattern.\n\n
|
||||||
loop also accepts conditionals to refine the looping further. Conditionals are of
|
loop also accepts conditionals to refine the looping further. Conditionals are of
|
||||||
the form:\n\n
|
the form:\n\n
|
||||||
\t:modifier argument\n\n
|
\t:modifier argument\n\n
|
||||||
@ -294,11 +296,9 @@
|
|||||||
(if (>= i len)
|
(if (>= i len)
|
||||||
(tuple.prepend body 'do)
|
(tuple.prepend body 'do)
|
||||||
(do
|
(do
|
||||||
(def {
|
(def {i bindings
|
||||||
i bindings
|
|
||||||
(+ i 1) verb
|
(+ i 1) verb
|
||||||
(+ i 2) object
|
(+ i 2) object} head)
|
||||||
} head)
|
|
||||||
(if (keyword? bindings)
|
(if (keyword? bindings)
|
||||||
(case bindings
|
(case bindings
|
||||||
:while (do
|
:while (do
|
||||||
@ -371,8 +371,25 @@
|
|||||||
(tuple 'def bindings (tuple get $indexed $i))
|
(tuple 'def bindings (tuple get $indexed $i))
|
||||||
subloop
|
subloop
|
||||||
(tuple ':= $i (tuple + 1 $i)))))
|
(tuple ':= $i (tuple + 1 $i)))))
|
||||||
|
:generate (do
|
||||||
|
(def $fiber (gensym))
|
||||||
|
(def $yieldval (gensym))
|
||||||
|
(def preds @['and
|
||||||
|
(do
|
||||||
|
(def s (gensym))
|
||||||
|
(tuple 'do
|
||||||
|
(tuple 'def s (tuple fiber.status $fiber))
|
||||||
|
(tuple 'or (tuple = s :pending) (tuple = s :new))))])
|
||||||
|
(def subloop (doone (+ i 3) preds))
|
||||||
|
(tuple 'do
|
||||||
|
(tuple 'def $fiber object)
|
||||||
|
(tuple 'var $yieldval (tuple resume $fiber))
|
||||||
|
(tuple 'while (tuple.slice preds 0)
|
||||||
|
(tuple 'def bindings $yieldval)
|
||||||
|
subloop
|
||||||
|
(tuple := $yieldval (tuple resume $fiber)))))
|
||||||
(error (string "unexpected loop verb: " verb)))))))
|
(error (string "unexpected loop verb: " verb)))))))
|
||||||
(doone 0 nil))
|
(tuple 'do (doone 0 nil) nil))
|
||||||
|
|
||||||
(defmacro fora
|
(defmacro fora
|
||||||
"Similar to loop, but accumulates the loop body into an array and returns that.
|
"Similar to loop, but accumulates the loop body into an array and returns that.
|
||||||
@ -398,6 +415,13 @@
|
|||||||
(tuple.prepend body 'do)))
|
(tuple.prepend body 'do)))
|
||||||
(tuple tuple.slice $accum 0)))
|
(tuple tuple.slice $accum 0)))
|
||||||
|
|
||||||
|
(defmacro generate
|
||||||
|
"Create a generator expression using the loop syntax. Returns a fiber
|
||||||
|
that yields all values inside the loop in order. See loop for details."
|
||||||
|
[head & body]
|
||||||
|
(tuple fiber.new
|
||||||
|
(tuple 'fn @[] (tuple 'loop head (tuple yield (tuple.prepend body 'do))))))
|
||||||
|
|
||||||
(defn sum [xs]
|
(defn sum [xs]
|
||||||
(var accum 0)
|
(var accum 0)
|
||||||
(loop [x :in xs] (+= accum x))
|
(loop [x :in xs] (+= accum x))
|
||||||
@ -1146,7 +1170,6 @@ value, one key will be ignored."
|
|||||||
(if (bytes? x) x (string.pretty x))
|
(if (bytes? x) x (string.pretty x))
|
||||||
"\n")
|
"\n")
|
||||||
(when f
|
(when f
|
||||||
(def st (fiber.stack f))
|
|
||||||
(loop
|
(loop
|
||||||
[{:function func
|
[{:function func
|
||||||
:tail tail
|
:tail tail
|
||||||
@ -1155,7 +1178,7 @@ value, one key will be ignored."
|
|||||||
:name name
|
:name name
|
||||||
:source source
|
:source source
|
||||||
:line source-line
|
:line source-line
|
||||||
:column source-col} :in st]
|
:column source-col} :in (fiber.stack f)]
|
||||||
(file.write stderr " in")
|
(file.write stderr " in")
|
||||||
(when c (file.write stderr " cfunction"))
|
(when c (file.write stderr " cfunction"))
|
||||||
(if name
|
(if name
|
||||||
@ -1329,7 +1352,7 @@ value, one key will be ignored."
|
|||||||
(def buf @"")
|
(def buf @"")
|
||||||
(default onvalue (fn [x]
|
(default onvalue (fn [x]
|
||||||
(put newenv '_ @{:value x})
|
(put newenv '_ @{:value x})
|
||||||
(print (string.pretty x 8 buf))
|
(print (string.pretty x 20 buf))
|
||||||
(buffer.clear buf)))
|
(buffer.clear buf)))
|
||||||
(default onerr default-error-handler)
|
(default onerr default-error-handler)
|
||||||
(run-context newenv getchunk onvalue onerr "repl"))
|
(run-context newenv getchunk onvalue onerr "repl"))
|
||||||
|
@ -46,6 +46,14 @@
|
|||||||
|
|
||||||
(assert (= txs '[[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]]) "nested for")
|
(assert (= txs '[[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]]) "nested for")
|
||||||
|
|
||||||
|
# Generators
|
||||||
|
(def gen (generate [x :range [0 100] :when (pos? (% x 4))] x))
|
||||||
|
(var gencount 0)
|
||||||
|
(loop [x :generate gen]
|
||||||
|
(++ gencount)
|
||||||
|
(assert (pos? (% x 4)) "generate in loop"))
|
||||||
|
(assert (= gencount 75) "generate loop count")
|
||||||
|
|
||||||
# Check x:digits: works as symbol and not a hex number
|
# Check x:digits: works as symbol and not a hex number
|
||||||
(def x1 100)
|
(def x1 100)
|
||||||
(assert (= x1 100) "x1 as symbol")
|
(assert (= x1 100) "x1 as symbol")
|
||||||
|
Loading…
Reference in New Issue
Block a user