MCPcopy Create free account
hub / github.com/cortex-js/compute-engine / zip

Function zip

src/compute-engine/collection-utils.ts:55–117  ·  view source on GitHub ↗
(items: ReadonlyArray<Expression>)

Source from the content-addressed store, hash-verified

53 * `Filter(xs, p)` used to answer `[]`, `Any(xs, p)` `False`, `All(xs, p)`
54 * `True`, `Find(xs, p)` `Nothing` and `IndexWhere(xs, p)` `0` for such a
55 * source — answers a later `xs := [1, 5]` contradicts, and which the rest of
56 * the library (`Length`, `Total`, `Sort`, `Map`, `CountIf`, …) has always
57 * declined to give by staying inert.
58 *
59 * An EAGER collection operator (`Characters(s)`, `Divisors(n)`, `Eigenvalues`,
60 * … — 73 of them, against 47 with collection handlers) has no collection
61 * handlers either until it is evaluated, and is the one case
62 * `isEnumerableCollection` reports `undefined` for. The evaluated form is
63 * consulted for exactly that case — off the hot path, since a source that is
64 * already a collection answers on the first test.
65 *
66 * **On the discarded evaluation** (measured 2026-08-09, don't re-litigate):
67 * the fallback fires only for a source that is not already a collection, and
68 * only at the LEAF of a chain — an inner `Filter`/`Map`/`Take` answers `true`
69 * on the first test. Measured at nesting depth 6 over `Characters(400)`: 12
70 * calls, 2 fallbacks; it does not compound with depth. The evaluated form is
71 * also what the subsequent walk materializes, and the lazy-collection evaluate
72 * memo keeps that second pass cheap.
73 *
74 * **Why the dedicated facet, and not the emptiness ones.**
75 * `isEmptyCollection`/`count` are HONEST about a valueless leaf (both
76 * `undefined`), and so is a wrapper over one (`Take(xs, 2)`, `Reverse(xs)`),
77 * where `isCollection` answers `true`. But reading them from here is
78 * **exponential**: `Filter.isEmpty` would call this, which reads the source's
79 * `isEmptyCollection`, which is the inner `Filter.isEmpty`, which calls this
80 * again — measured at exactly 2^(d+1) − 2 calls (6/14/30/62/126/254 at depths
81 * 2–7), the double-read shape-query class. `isEnumerableCollection` is the
82 * O(1) propagating facet that answers instead: a wrapper reads only its
83 * source's enumerability (never its own emptiness), so a depth-d chain costs
84 * d calls.
85 *
86 * **On evaluating an IMPURE source.** The fallback evaluates `xs` and throws
87 * the result away, so an eager IMPURE producer (`RandomShuffle`) runs one
88 * extra time. That is a pre-existing property of these paths rather than
89 * something this predicate introduced: counting handler invocations for a
90 * 5-element source, `Map(f, RandomShuffle(xs))` — which never reaches this
91 * function — evaluates the shuffle **8** times, `Filter(RandomShuffle(xs), p)`
92 * 5 (of which this contributes 1), `Any(…)` 2. The results stay correct (a
93 * filtered shuffle is still a filtered shuffle); what is not reproducible is
94 * the number of draws consumed. Tracked in `ROADMAP.md` as its own defect —
95 * fixing it here alone would not make the path reproducible.
96 *
97 * **Asymmetry with {@link isBroadcastableCollection}** — deliberate. That
98 * predicate has no such fallback because it answers a different question at a
99 * different place: it is consulted on operands that have ALREADY been
100 * evaluated (the broadcast gates run post-evaluation), and it fails CLOSED —
101 * a `false` means "do not broadcast", which leaves the expression symbolic.
102 * This one is consulted inside LAZY collection handlers, where the source may
103 * still be raw, and a wrong answer produces a definite wrong VALUE. Accuracy
104 * is worth an evaluation here and is not needed there.
105 */
106export function isEnumerableSource(xs: Expression): boolean {
107 // The facet answers structurally for everything that can be decided without
108 // evaluating: a leaf collection (`true`), a symbolic-bounds `Range` or a
109 // valueless symbol (`false`), and a wrapper over either (propagated).
110 const enumerable = xs.isEnumerableCollection;
111 if (enumerable !== undefined) return enumerable;
112

Callers 4

_computeValueMethod · 0.90
_computeValueAsyncMethod · 0.90
applyFunctionLiteralFunction · 0.90
sampleFunction · 0.85

Calls 3

repeatFunction · 0.85
eachMethod · 0.65
mapMethod · 0.65

Tested by

no test coverage detected