2020-11-28 14:53:18 +03:00
(defmacro for [settings :rest body] ;; settings = variable, from, to, <step>
(if (> (length body) 1)
(macro-error "Warning: the body of the 'for' loop can only contain one expression")
(let [variable (car settings)
from (cadr settings)
to (caddr settings)
step (if (> (length settings) 3) (cadddr settings) 1)
comp (if (> (length settings) 4)
(cadddr (cdr settings))
(if (< step (- step step)) '> '<))
]
2021-01-21 08:20:03 +03:00
`(let [%variable %from]
(while (%comp %variable %to)
(do
%(cond
(= (length body) 0) ()
(list? body) (car body)
body)
(set! %variable (+ %variable %step))))))))
2020-11-28 14:53:18 +03:00
2021-07-05 15:48:35 +03:00
(doc Array "is the indexable collection data structure.
Its literal uses brackets, so an array of integers would look like this:
`[1 2 3]`. It provides both a functional and an imperative API, and is one of
the core data structures of Carp. It is heap-allocated, for a stack-allocated
variant you might want to check out [`StaticArray`](./StaticArray.html).")
2017-06-26 12:15:03 +03:00
(defmodule Array
2019-02-15 12:18:23 +03:00
(doc reduce "will reduce an array `xs` into a single value using a function `f` that takes the reduction thus far and the next value. The initial reduction value is `x`.
As an example, consider this definition of `sum` based on `reduce`:
```
(defn sum [x]
2020-01-07 01:29:49 +03:00
(reduce &(fn [x y] (+ x @y)) 0 x))
2019-02-15 12:18:23 +03:00
```
It will sum the previous sum with each new value, starting at `0`.")
2017-10-17 09:57:36 +03:00
(defn reduce [f x xs]
(let [total x]
(do
2018-05-20 10:57:51 +03:00
(for [i 0 (length xs)]
2019-10-31 12:23:23 +03:00
(set! total (~f total (unsafe-nth xs i))))
2017-10-17 09:57:36 +03:00
total)))
2017-10-26 18:37:44 +03:00
2021-10-22 07:59:40 +03:00
(doc scan "Similar to `Array.reduce`, but instead returns an array with the starting element,
and then all intermediate values.
For example, a scan using `Int.+` over the array [1 1 1 1 1] (starting at 0) will return [0 1 2 3 4 5].")
(defn scan [f x xs]
(let [n (length xs)
ys (allocate (inc n))]
(do
(aset-uninitialized! &ys 0 @&x)
(for [i 1 (inc n)]
(aset-uninitialized! &ys i (~f (unsafe-nth &ys (dec i)) (unsafe-nth xs (dec i)))))
ys)))
(doc endo-scan "Like `Array.scan`, but uses the first element of the array as the starting value.
Also does not create a new array, but reuses the initial one instead (by taking ownership over `xs`.)
For example, an endo-scan using `Int.+` over the array [1 1 1 1 1] will return [1 2 3 4 5]")
(defn endo-scan [f xs]
(let [n (length &xs)]
(do
(for [i 1 n]
(aset! &xs i (~f (unsafe-nth &xs (dec i)) (unsafe-nth &xs i))))
xs)))
2019-02-15 12:18:23 +03:00
(doc empty? "checks whether the array `a` is empty.")
2018-11-08 20:01:31 +03:00
(defn empty? [a]
(= (Array.length a) 0))
2021-01-20 11:54:08 +03:00
(implements empty? Array.empty?)
2018-11-08 20:01:31 +03:00
2019-02-15 12:18:23 +03:00
(doc any? "checks whether any of the elements in `a` match the function `f`.")
2018-11-08 21:13:02 +03:00
(defn any? [f a]
2018-11-08 21:31:54 +03:00
(let-do [res false]
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (~f (unsafe-nth a i))
2018-11-08 21:31:54 +03:00
(do
(set! res true)
(break))))
res))
2018-11-08 21:13:02 +03:00
2019-02-15 12:18:23 +03:00
(doc all? "checks whether all of the elements in `a` match the function `f`.")
2018-11-08 21:13:02 +03:00
(defn all? [f a]
2018-11-08 21:31:54 +03:00
(let-do [res true]
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (not (~f (unsafe-nth a i)))
2018-11-08 21:31:54 +03:00
(do
(set! res false)
(break))))
res))
2018-11-08 21:13:02 +03:00
2019-05-13 20:47:03 +03:00
(doc find "finds an element in `a` that matches the function `f` and wraps it in a `Just`.
If it doesn’ t find an element, `Nothing` will be returned.")
2018-11-08 21:13:02 +03:00
(defn find [f a]
2019-05-13 20:47:03 +03:00
(let-do [res (Maybe.Nothing)]
2018-11-08 21:13:02 +03:00
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (~f (unsafe-nth a i))
2018-11-08 21:13:02 +03:00
(do
2019-10-31 12:23:23 +03:00
(set! res (Maybe.Just @(unsafe-nth a i)))
2018-11-08 21:13:02 +03:00
(break))))
res))
2019-02-15 12:18:23 +03:00
(doc find-index "finds the index of the first element in `a` that matches the function `f` and wraps it in a `Just`.
If it doesn’ t find an index, `Nothing` will be returned.")
2018-12-18 17:30:09 +03:00
(defn find-index [f a]
2019-02-15 12:18:23 +03:00
(let-do [ret (Maybe.Nothing)]
2018-12-18 17:30:09 +03:00
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (~f (unsafe-nth a i))
2018-12-18 17:30:09 +03:00
(do
2019-02-15 12:18:23 +03:00
(set! ret (Maybe.Just i))
2018-12-18 17:30:09 +03:00
(break))))
ret))
2019-02-15 12:18:23 +03:00
(doc unsafe-first "takes the first element of an array.
Generates a runtime error if the array is empty.")
(defn unsafe-first [a]
2020-11-27 12:19:06 +03:00
(Array.unsafe-nth a 0))
2017-11-29 17:28:21 +03:00
2019-02-15 12:18:23 +03:00
(doc first "takes the first element of an array and returns a `Just`.
Returns `Nothing` if the array is empty.")
(defn first [a]
(if (empty? a)
(Maybe.Nothing)
2019-10-31 12:23:23 +03:00
(Maybe.Just @(Array.unsafe-nth a 0))))
2019-02-15 12:18:23 +03:00
(doc unsafe-last "takes the last element of an array.
Generates a runtime error if the array is empty.")
(defn unsafe-last [a]
2020-11-27 12:19:06 +03:00
(Array.unsafe-nth a (Int.dec (Array.length a))))
2017-12-04 09:21:35 +03:00
2019-02-15 12:18:23 +03:00
(doc last "takes the last element of an array and returns a `Just`.
Returns `Nothing` if the array is empty.")
(defn last [a]
(if (empty? a)
(Maybe.Nothing)
2019-10-31 12:23:23 +03:00
(Maybe.Just @(Array.unsafe-nth a (Int.dec (Array.length a))))))
2019-02-15 12:18:23 +03:00
(doc = "compares two arrays.")
2017-12-19 14:46:46 +03:00
(defn = [a b]
2018-05-20 10:57:51 +03:00
(if (/= (length a) (length b))
2017-12-19 14:46:46 +03:00
false
(let-do [eq true]
2018-05-20 10:57:51 +03:00
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (/= (unsafe-nth a i) (unsafe-nth b i))
2017-12-19 14:46:46 +03:00
(do
2018-02-02 09:19:10 +03:00
(set! eq false)
2017-12-19 14:46:46 +03:00
(break))))
eq)))
2020-05-10 20:32:22 +03:00
(implements = Array.=)
2017-12-19 14:46:46 +03:00
2020-05-02 15:18:14 +03:00
(doc maximum "gets the maximum in an array (elements must support `<`) and wraps it in a `Just`.
2019-05-14 03:41:45 +03:00
2019-05-14 17:57:50 +03:00
If the array is empty, it returns `Nothing`.")
2018-01-29 09:14:41 +03:00
(defn maximum [xs]
2019-05-14 17:57:50 +03:00
(if (empty? xs)
(Maybe.Nothing)
2019-10-31 12:23:23 +03:00
(let-do [result (unsafe-nth xs 0)
2019-05-14 17:57:50 +03:00
n (length xs)]
2018-01-29 12:55:45 +03:00
(for [i 1 n]
2019-10-31 12:23:23 +03:00
(let [x (unsafe-nth xs i)]
2019-05-14 17:57:50 +03:00
(when (< result x)
(set! result x))))
(Maybe.Just @result))))
2017-12-04 09:21:35 +03:00
2019-05-14 17:57:50 +03:00
(doc minimum "gets the minimum in an array (elements must support `>`) and wraps it in a `Just`.
2019-05-14 03:41:45 +03:00
If the array is empty, returns `Nothing`")
2018-01-29 09:14:41 +03:00
(defn minimum [xs]
2019-05-14 17:57:50 +03:00
(if (empty? xs)
(Maybe.Nothing)
2019-10-31 12:23:23 +03:00
(let-do [result (unsafe-nth xs 0)
2020-05-02 15:18:14 +03:00
n (length xs)]
2018-01-29 12:55:45 +03:00
(for [i 1 n]
2019-10-31 12:23:23 +03:00
(let [x (unsafe-nth xs i)]
2019-05-14 19:29:30 +03:00
(when (> result x)
2019-05-14 17:57:50 +03:00
(set! result x))))
(Maybe.Just @result))))
2017-12-04 09:21:35 +03:00
2019-05-13 20:47:03 +03:00
(doc sum "sums an array (elements must support `+` and `zero`).")
2017-12-04 09:21:35 +03:00
(defn sum [xs]
2018-11-14 16:09:43 +03:00
(Array.reduce &(fn [x y] (+ x @y)) (zero) xs))
2017-12-08 17:12:50 +03:00
2020-02-11 11:09:30 +03:00
(doc slice "gets a subarray from `start-index` to `end-index`.")
(defn slice [xs start-index end-index]
2019-05-14 03:41:45 +03:00
(let-do [result []]
(for [i start-index end-index]
2019-10-31 12:23:23 +03:00
(set! result (push-back result @(unsafe-nth xs i))))
2019-05-14 03:41:45 +03:00
result))
2020-05-10 20:32:22 +03:00
(implements slice Array.slice)
2017-12-18 18:53:46 +03:00
2020-02-11 11:09:30 +03:00
(doc prefix "gets a prefix array to `end-index`.")
(defn prefix [xs end-index]
(slice xs 0 end-index))
2017-12-19 14:46:46 +03:00
2020-02-11 11:09:30 +03:00
(doc suffix "gets a suffix array from `start-index`.")
(defn suffix [xs start-index]
(slice xs start-index (length xs)))
2017-12-19 14:46:46 +03:00
2020-12-24 18:19:53 +03:00
(doc rest "gets all but the first element from the array.")
(defn rest [xs]
(suffix xs 1))
2019-02-15 12:18:23 +03:00
(doc reverse "reverses an array.")
2017-12-18 18:53:46 +03:00
(defn reverse [a]
(let-do [i 0
2018-05-20 10:57:51 +03:00
j (Int.dec (length &a))]
2017-12-18 18:53:46 +03:00
(while (Int.< i j)
2019-10-31 12:23:23 +03:00
(let-do [tmp @(unsafe-nth &a i)]
(aset! &a i @(unsafe-nth &a j))
2018-02-02 09:19:10 +03:00
(set! i (Int.inc i))
2017-12-18 18:53:46 +03:00
(aset! &a j tmp)
2018-02-02 09:19:10 +03:00
(set! j (Int.dec j))))
2017-12-18 18:53:46 +03:00
a))
2018-01-02 16:39:24 +03:00
2019-05-14 12:53:19 +03:00
(doc index-of "gets the index of element `e` in an array and wraps it on a `Just`.
If the element is not found, returns `Nothing`")
2018-01-02 16:39:24 +03:00
(defn index-of [a e]
2019-05-14 12:48:26 +03:00
(let-do [idx (Maybe.Nothing)]
2018-05-20 10:57:51 +03:00
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (= (unsafe-nth a i) e)
2018-01-02 16:39:24 +03:00
(do
2019-05-14 12:48:26 +03:00
(set! idx (Maybe.Just i))
2018-01-02 16:39:24 +03:00
(break))))
idx))
2019-02-15 12:18:23 +03:00
(doc element-count "counts the occurrences of element `e` in an array.")
2018-01-02 16:39:24 +03:00
(defn element-count [a e]
(let-do [c 0]
2018-05-20 10:57:51 +03:00
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (= e (unsafe-nth a i)) (set! c (Int.inc c))))
2018-12-18 17:30:09 +03:00
c))
2019-02-15 12:18:23 +03:00
(doc predicate-count "counts the number of elements satisfying the predicate function `pred` in an array.")
2018-12-18 17:30:09 +03:00
(defn predicate-count [a pred]
(let-do [c 0]
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(when (~pred (unsafe-nth a i))
2018-12-18 17:30:09 +03:00
(set! c (Int.inc c))))
2018-01-02 16:39:24 +03:00
c))
2018-01-02 20:13:52 +03:00
2021-05-25 13:11:31 +03:00
(doc unsafe-nth-value "returns the value at index `i` of an array `a` (just like [unsafe-nth](#unsafe-nth)) but does not take its reference, and does *not* copy the value. Should only be used for optimizations and when you know what you're doing, circumvents the borrow checker!")
(deftemplate unsafe-nth-value (Fn [(Ref (Array a)) Int] a)
"$a $NAME(Array *a, int i)"
"$DECL { return (($a*)a->data)[i]; }")
2019-02-15 12:18:23 +03:00
(doc aupdate "transmutes (i.e. updates) the element at index `i` of an array `a` using the function `f`.")
2018-01-02 20:13:52 +03:00
(defn aupdate [a i f]
2021-05-25 13:11:31 +03:00
(do
(aset-uninitialized! &a i (~f (unsafe-nth-value &a i)))
a))
2018-01-02 20:13:52 +03:00
2019-02-15 12:18:23 +03:00
(doc aupdate! "transmutes (i.e. updates) the element at index `i` of an array `a` using the function `f` in place.")
2018-01-02 20:13:52 +03:00
(defn aupdate! [a i f]
2021-05-25 13:11:31 +03:00
(aset-uninitialized! a i (~f (unsafe-nth-value a i))))
2018-01-02 20:13:52 +03:00
2019-02-15 12:18:23 +03:00
(doc swap "swaps the indices `i` and `j` of an array `a`.")
2018-01-02 20:13:52 +03:00
(defn swap [a i j]
2019-10-31 12:23:23 +03:00
(let [x @(unsafe-nth &a i)
y @(unsafe-nth &a j)]
2018-03-11 12:38:24 +03:00
(aset (aset a i y) j x)))
2018-01-02 20:13:52 +03:00
2019-02-15 12:18:23 +03:00
(doc swap! "swaps the indices `i` and `j` of an array `a` in place.")
2018-01-02 20:13:52 +03:00
(defn swap! [a i j]
2019-10-31 12:23:23 +03:00
(let-do [x @(unsafe-nth a i)
y @(unsafe-nth a j)]
2018-01-02 20:13:52 +03:00
(aset! a i y)
(aset! a j x)))
2019-02-15 12:18:23 +03:00
(doc repeat "repeats the function `f` `n` times and stores the results in an array.")
2018-01-24 16:07:43 +03:00
(defn repeat [n f]
(let-do [a (allocate n)]
2018-11-14 16:09:43 +03:00
(for [i 0 n] (aset-uninitialized! &a i (~f)))
2018-01-24 16:07:43 +03:00
a))
2019-09-08 14:02:04 +03:00
(doc repeat-indexed "repeats function `f` `n` times and stores the results in an array.
2019-02-15 12:18:23 +03:00
This is similar to [`repeat`](#repeat), but the function `f` will be supplied with the index of the element.")
2018-01-24 16:07:43 +03:00
(defn repeat-indexed [n f]
(let-do [a (allocate n)]
2018-03-12 16:37:53 +03:00
(for [i 0 n] (aset-uninitialized! &a i (f i)))
2018-01-24 16:07:43 +03:00
a))
2019-02-15 12:18:23 +03:00
(doc replicate "repeats element `e` `n` times and stores the results in an array.")
2018-01-24 16:07:43 +03:00
(defn replicate [n e]
(let-do [a (allocate n)]
2018-03-12 16:37:53 +03:00
(for [i 0 n] (aset-uninitialized! &a i @e))
2018-01-24 16:07:43 +03:00
a))
2018-01-24 16:41:50 +03:00
2019-02-15 12:18:23 +03:00
(doc copy-map "maps over an array `a` using the function `f`.
This function copies the array. If you don’ t want that, use [`endo-map`](#endo-map).")
2018-01-24 16:41:50 +03:00
(defn copy-map [f a]
2018-05-20 10:57:51 +03:00
(let-do [na (allocate (length a))]
(for [i 0 (length a)]
2019-10-31 12:23:23 +03:00
(aset-uninitialized! &na i (~f (unsafe-nth a i))))
2018-01-24 16:41:50 +03:00
na))
2018-04-23 13:20:00 +03:00
2019-11-21 13:05:21 +03:00
(doc unreduce "creates an array by producing values using `step` until they
no longer satisfy `test`. The initial value is `start`.
2019-11-13 12:47:22 +03:00
Example:
```
; if we didn’ t have Array.range, we could define it like this:
(defn range [start end step]
2019-11-21 13:05:21 +03:00
(unreduce start &(fn [x] (< x (+ step end))) &(fn [x] (+ x step)))
2019-11-13 12:47:22 +03:00
)
```")
2019-11-21 13:05:21 +03:00
(defn unreduce [start test step]
2019-11-13 12:47:22 +03:00
(let-do [elem start
acc []]
(while-do (~test elem)
(push-back! &acc elem)
(set! elem (~step elem)))
acc))
2019-02-15 12:18:23 +03:00
(doc zip "maps over two arrays using a function `f` that takes two arguments. It will produces a new array with the length of the shorter input.
The trailing elements of the longer array will be discarded.")
2018-06-01 12:18:03 +03:00
(defn zip [f a b]
2020-04-10 20:52:01 +03:00
(let-do [l (min (length a) (length b))
2018-06-01 12:00:50 +03:00
na (allocate l)]
(for [i 0 l]
2019-10-31 12:23:23 +03:00
(aset-uninitialized! &na i (~f (unsafe-nth a i) (unsafe-nth b i))))
2018-06-01 12:00:50 +03:00
na))
2019-02-15 12:18:23 +03:00
(doc sum-length "returns the sum of lengths from a nested array `xs`.")
2018-05-20 10:57:51 +03:00
(defn sum-length [xs]
2018-05-20 10:20:57 +03:00
(let-do [sum 0
2018-05-20 10:57:51 +03:00
lxs (Array.length xs)]
2018-05-20 10:20:57 +03:00
(for [i 0 lxs]
2019-10-31 12:23:23 +03:00
(set! sum (+ sum (Array.length (Array.unsafe-nth xs i)))))
2018-05-20 10:20:57 +03:00
sum))
2019-02-15 12:18:23 +03:00
(doc zero "returns the empty array.")
2018-08-06 21:47:09 +03:00
(defn zero [] [])
2020-05-09 19:59:47 +03:00
(implements zero Array.zero)
2018-08-06 21:47:09 +03:00
2019-02-15 12:18:23 +03:00
(doc concat "returns a new array which is the concatenation of the provided nested array `xs`.")
2018-04-23 13:20:00 +03:00
(defn concat [xs]
2018-05-20 10:20:57 +03:00
;; This is using a StringBuilder pattern to only perform one allocation and
;; to only copy each of the incoming Array(s) once.
2018-05-20 10:57:51 +03:00
;; This currently performs wasted Array.length calls, as we call it for each
;; Array once here and once in sum-length.
2018-05-20 10:20:57 +03:00
(let-do [j 0
2018-05-20 10:57:51 +03:00
lxs (Array.length xs)
result (Array.allocate (sum-length xs))]
2018-05-20 10:20:57 +03:00
(for [i 0 lxs]
2019-10-31 12:23:23 +03:00
(let-do [arr (Array.unsafe-nth xs i)
2018-05-20 10:57:51 +03:00
len (Array.length arr)]
2018-05-20 10:20:57 +03:00
(for [k 0 len]
2019-10-31 12:23:23 +03:00
(aset-uninitialized! &result (+ j k) @(Array.unsafe-nth arr k)))
2018-05-20 10:20:57 +03:00
(set! j (+ j len))))
2018-04-23 13:20:00 +03:00
result))
2018-06-01 12:00:50 +03:00
2019-02-15 12:18:23 +03:00
(doc enumerated "creates a new array of `Pair`s where the first position is the index and the second position is the element from the original array `xs`.")
2018-06-01 12:00:50 +03:00
(defn enumerated [xs]
2020-05-11 21:50:40 +03:00
(let-do [arr (allocate (length xs))]
(for [i 0 (length xs)]
(aset-uninitialized!
&arr
i
(Pair.init-from-refs &i (unsafe-nth xs i))))
arr))
2018-12-07 14:56:10 +03:00
2019-11-01 01:14:44 +03:00
(doc nth "gets a reference to the `n`th element from an array `arr` wrapped on a `Maybe`.
If the `index` is out of bounds, return `Maybe.Nothing`")
2019-11-01 09:19:02 +03:00
(defn nth [xs index]
2020-05-02 15:18:14 +03:00
(if (and (>= index 0) (< index (length xs)))
(Maybe.Just @(unsafe-nth xs index)) ; the copy will go away with lifetimes
(Maybe.Nothing)))
2019-11-01 01:14:44 +03:00
2019-02-15 12:18:23 +03:00
(doc remove "removes all occurrences of the element `el` in the array `arr`, in place.")
2018-12-07 14:56:10 +03:00
(defn remove [el arr]
2019-02-02 12:29:13 +03:00
(endo-filter &(fn [x] (not (= el x)))
arr))
2018-12-07 14:56:10 +03:00
2019-02-15 12:18:23 +03:00
(doc remove-nth "removes element at index `idx` from the array `arr`.")
2018-12-07 19:32:56 +03:00
(defn remove-nth [i arr]
2018-12-07 15:00:52 +03:00
(do
;;(assert (<= 0 i))
;;(assert (< i (Array.length &arr)))
(for [j i (Int.dec (Array.length &arr))]
2019-10-31 12:23:23 +03:00
(aset! &arr j @(unsafe-nth &arr (inc j))))
2018-12-07 15:00:52 +03:00
(pop-back arr)))
2019-02-02 12:29:13 +03:00
2020-05-02 15:18:14 +03:00
(doc copy-filter "filters the elements in an array.
2019-02-15 12:18:23 +03:00
It will create a copy. If you want to avoid that, consider using [`endo-filter`](#endo-filter) instead.")
2019-09-16 16:33:18 +03:00
(defn copy-filter [f a] (endo-filter f @a))
(doc contains? "checks wether an element exists in the array.")
(defn contains? [arr el]
(let-do [result false]
(for [i 0 (Array.length arr)]
2019-10-31 12:23:23 +03:00
(when (= el (Array.unsafe-nth arr i))
2019-09-16 16:33:18 +03:00
(do
(set! result true)
(break))))
result))
2020-02-16 23:57:38 +03:00
(doc partition
"Partitions an array `arr` into an array of arrays of length `n`
sequentially filled with the `arr`'s original values.
This function will fill partitions until `arr` is exhuasted.
If `n` is greater than or equal to the length of `arr`, the result of this
function is an array containing a single array of length `n`.
For example:
```clojure
(Array.partition &[1 2 3 4] 2)
=> [[1 2] [3 4]]
(Array.partition &[1 2 3 4] 3)
=> [[1 2 3] [4]]
(Array.partition &[1 2 3 4] 6)
=> [[1 2 3 4]]
```")
(sig partition (Fn [(Ref (Array a) b) Int] (Array (Array a))))
2020-05-06 11:27:10 +03:00
(defn partition [arr n]
2020-02-16 23:57:38 +03:00
(let-do [x 0
y 0
a []]
;; We use while since we're doing custom incrementation of x
;; dealing with the extra increment implicitly called by for is messier
(while (< x (Array.length arr))
(do
(set! y (+ x n))
(when (> y (Array.length arr))
(set! y (Array.length arr)))
(set! a (push-back a (Array.slice arr x y)))
(set! x y)))
2020-05-03 14:15:36 +03:00
a))
(doc from-static "Turns a `StaticArray` into an `Array`. Copies elements.")
(defn from-static [sarr]
(let-do [darr (allocate (StaticArray.length sarr))]
(for [i 0 (StaticArray.length sarr)]
(aset-uninitialized! &darr i @(StaticArray.unsafe-nth sarr i)))
2021-04-19 17:45:15 +03:00
darr))
(doc map-reduce "reduces an array `a` by invoking the function `f` on each
element, while keeping an accumulator and a list.
Returns a `Pair` where the first element is the mapped array and the second one
is the final accumulator.
2021-04-20 10:52:24 +03:00
The function `f` receives two arguments: the first one is the accumulator, and
the second one is the element. `f` must return `(Pair accumulator result)`.
2021-04-19 17:45:15 +03:00
Example:
```
(map-reduce &(fn [acc x] (Pair.init (+ @x @acc) (* @x 2))) 0 &[1 2 3])
; => (Pair 6 [2 4 6])
```")
(defn map-reduce [f acc a]
(reduce
&(fn [a el]
(let [l (Pair.b &a)
acc (Pair.a &a)
p (~f acc el)]
(Pair.init @(Pair.a &p) (Array.push-back @l @(Pair.b &p)))))
(Pair.init acc [])
a))
)
2020-11-28 14:53:18 +03:00
(defmacro doall [f xs]
2021-01-21 08:20:03 +03:00
`(for [i 0 (Array.length &%xs)]
(%f (Array.unsafe-nth &%xs i))))
2020-11-28 14:53:18 +03:00
(defndynamic foreach-internal [var xs expr]
(let [xsym (gensym-with 'xs)
len (gensym-with 'len)
i (gensym-with 'i)]
2021-01-21 08:20:03 +03:00
`(let [%xsym %xs
%len (Array.length %xsym)]
(for [%i 0 %len]
(let [%var (Array.unsafe-nth %xsym %i)]
%expr)))))
2020-11-28 14:53:18 +03:00
(defmacro foreach [binding expr]
(if (array? binding)
(foreach-internal (car binding) (cadr binding) expr)
(macro-error "Binding has to be an array.")))