Add missing List ops; short-circuit any?/all? in all types#13
Add missing List ops; short-circuit any?/all? in all types#13carpentry-agent[bot] wants to merge 1 commit into
Conversation
Add nth, take, find, and contains? to persistent List. Rewrite any? and all? for all 11 collection types to short-circuit instead of walking every element via reduce.
There was a problem hiding this comment.
Build & Tests
Build: compiles cleanly on ARM Linux.
Tests: all 236 tests pass across 9 collection types (list 41, queue 26, deque 24, ord-map 35, ord-set 23, heap 16, hash-map 28, hash-set 22, vector 21). Trie tests crash under ASan on ARM due to a pre-existing stack overflow in get-in-siblings (confirmed on main — not introduced by this PR).
CI: passing on both macos-latest and ubuntu-latest.
Findings
1. Hash map any?/all? don't fully short-circuit within collision/bitmap nodes (persistent.carp:3292–3305). The for loop continues iterating after result is set — the guard (when (and (not result) ...)) prevents work but not iteration. In practice this is harmless since collision nodes are typically small and HAMT bitmap nodes have at most 32 slots, but it's worth knowing it's O(node-size) per node rather than truly breaking out.
2. All four new list operations are correct:
nth(line 248): bounds-checked with negative index handling, O(n) traversal with early exit onMaybe.Nothing.take(line 268): clampsnto list length, builds in reverse then callsreverse— correct order.find(line 290): early exit on match viakeep-goingflag.contains?(line 308): early exit on equality match.
3. All any?/all? rewrites are correct across all 11 collection types. Each uses an appropriate traversal strategy:
- List: manual walk with
keep-goingflag - Queue/Deque: delegate to list's short-circuiting versions (front then reversed rear)
- Trie: stack-based DFS maintaining a
patharray for key reconstruction — complex but well-structured - Ordered Map: Morris-style in-order traversal with explicit stack — correct
- Ordered Set: delegates to Ordered Map
- Heap: stack-based DFS over left/right children
- Hash Map: stack-based HAMT traversal with per-node
forloops (see finding #1) - Hash Set: delegates to Hash Map
- Vector: index loop with
(< i n)and result flag
4. deftemplate formatting changes (lines 9–19) are whitespace-only reformatting of popcount and array-reserve!. Correct and harmless.
Verdict: merge
Large but well-structured change. All 236 tests pass, CI is green. Finding #1 is a minor performance note, not a correctness issue. The new list operations fill real gaps, and the any?/all? rewrites correctly eliminate the reduce-based full traversal across all collection types.
Summary
nth,take,find,contains?— basic operations users expect from a persistent list (O(n) element access, prefix slicing, search, membership test), all with proper early exit.any?/all?: Rewrote both predicates across all 11 collection types (List, Queue, Deque, Trie, Ordered Map, Ordered Set, Heap, Hash Map, Hash Set, Vector) to stop as soon as the answer is known instead of walking every element viareduce.What changed per type
any?/all?approachTest plan
carp-fmt -ccleananglerfindings fixed in new codeOpened by the carpentry-org heartbeat agent (Claude). hellerve has not reviewed this yet.