mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +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() {
|
||||
|
||||
JanetTable *t1;
|
||||
JanetTable *t1, *t2;
|
||||
|
||||
janet_init();
|
||||
|
||||
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("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("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();
|
||||
|
||||
return 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
# A game of life implementation
|
||||
|
||||
(def- windows
|
||||
(def- window
|
||||
(fora [x :range [-1 2]
|
||||
y :range [-1 2]
|
||||
:when (not (and (zero? x) (zero? y)))]
|
||||
@ -8,38 +8,37 @@
|
||||
|
||||
(defn- neighbors
|
||||
[[x y]]
|
||||
(mapa (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) windows))
|
||||
(mapa (fn [[x1 y1]] (tuple (+ x x1) (+ y y1))) window))
|
||||
|
||||
(defn tick
|
||||
"Get the next state in the Game Of Life."
|
||||
[state]
|
||||
(def neighbor-set (frequencies (mapcat neighbors (keys state))))
|
||||
(def next-state @{})
|
||||
(loop [coord :keys neighbor-set
|
||||
:let [count (get neighbor-set coord)]]
|
||||
(if (if (get state coord)
|
||||
(or (= count 2) (= count 3))
|
||||
(= count 3))
|
||||
(put next-state coord true)))
|
||||
next-state)
|
||||
(def cell-set (frequencies state))
|
||||
(def neighbor-set (frequencies (mapcat neighbors state)))
|
||||
(fora [coord :keys neighbor-set
|
||||
:let [count (get neighbor-set coord)]
|
||||
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
|
||||
coord))
|
||||
|
||||
(defn draw
|
||||
"Draw cells in the game of life from (x1, y1) to (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))) "+")
|
||||
:after (print "+" (string.repeat "--" (inc (- y2 y1))) "+")
|
||||
x :range [x1 (+ 1 x2)]
|
||||
:before (file.write stdout "|")
|
||||
:after (file.write stdout "|\n")
|
||||
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))
|
||||
|
||||
#
|
||||
# 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]]
|
||||
(print "generation " i)
|
||||
|
@ -271,7 +271,9 @@
|
||||
\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
|
||||
\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
|
||||
the form:\n\n
|
||||
\t:modifier argument\n\n
|
||||
@ -294,11 +296,9 @@
|
||||
(if (>= i len)
|
||||
(tuple.prepend body 'do)
|
||||
(do
|
||||
(def {
|
||||
i bindings
|
||||
(def {i bindings
|
||||
(+ i 1) verb
|
||||
(+ i 2) object
|
||||
} head)
|
||||
(+ i 2) object} head)
|
||||
(if (keyword? bindings)
|
||||
(case bindings
|
||||
:while (do
|
||||
@ -371,8 +371,25 @@
|
||||
(tuple 'def bindings (tuple get $indexed $i))
|
||||
subloop
|
||||
(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)))))))
|
||||
(doone 0 nil))
|
||||
(tuple 'do (doone 0 nil) nil))
|
||||
|
||||
(defmacro fora
|
||||
"Similar to loop, but accumulates the loop body into an array and returns that.
|
||||
@ -398,6 +415,13 @@
|
||||
(tuple.prepend body 'do)))
|
||||
(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]
|
||||
(var accum 0)
|
||||
(loop [x :in xs] (+= accum x))
|
||||
@ -1146,7 +1170,6 @@ value, one key will be ignored."
|
||||
(if (bytes? x) x (string.pretty x))
|
||||
"\n")
|
||||
(when f
|
||||
(def st (fiber.stack f))
|
||||
(loop
|
||||
[{:function func
|
||||
:tail tail
|
||||
@ -1155,7 +1178,7 @@ value, one key will be ignored."
|
||||
:name name
|
||||
:source source
|
||||
:line source-line
|
||||
:column source-col} :in st]
|
||||
:column source-col} :in (fiber.stack f)]
|
||||
(file.write stderr " in")
|
||||
(when c (file.write stderr " cfunction"))
|
||||
(if name
|
||||
@ -1329,7 +1352,7 @@ value, one key will be ignored."
|
||||
(def buf @"")
|
||||
(default onvalue (fn [x]
|
||||
(put newenv '_ @{:value x})
|
||||
(print (string.pretty x 8 buf))
|
||||
(print (string.pretty x 20 buf))
|
||||
(buffer.clear buf)))
|
||||
(default onerr default-error-handler)
|
||||
(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")
|
||||
|
||||
# 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
|
||||
(def x1 100)
|
||||
(assert (= x1 100) "x1 as symbol")
|
||||
|
Loading…
Reference in New Issue
Block a user