Skip to content

feat(core): seqable hash-maps and sets, sequential destructuring#133

Merged
jig merged 2 commits into
developfrom
feat/seqable-hashmaps
Jul 24, 2026
Merged

feat(core): seqable hash-maps and sets, sequential destructuring#133
jig merged 2 commits into
developfrom
feat/seqable-hashmaps

Conversation

@jig

@jig jig commented Jul 24, 2026

Copy link
Copy Markdown
Owner

What

Hash-maps and sets are now seqable, as in Clojure, and binding forms gain sequential destructuring:

(into {} (map (fn [[k v]] [k (- v)]) {:seconds 5 :days 2}))
;;=> {:seconds -5 :days -2}
  • A hash-map seqs as a sequence of [key value] entry vectors, a set as a sequence of its elements — implemented at a single choke point, types.GetSlice (plus ConvertFrom for vec and a seq case). seq, first, rest, map, filter, reduce, apply, cons, concat, vec, into and lazy-seqs work over both.
  • Keys/elements are returned exactly as stored (what keys already does), in sorted order. Sorting is a correctness requirement, not cosmetics: first and rest each seq the collection independently, and Go randomises map iteration per call, so an unstable order makes a first/rest traversal (lisp-level reduce/filter) drop or repeat entries.
  • nth explicitly rejects hash-maps and sets: they seq, but are not indexed collections (Clojure errors here too), and returning a sorted-order element would invite position-dependent code.
  • Sequential destructuring in fn params and let bindings ((fn [[k v]] …), (let [[a [b c]] x] …)): positional and recursive, missing elements bind nil, extra are ignored, & binds the remainder as a list. The language previously only had & varargs, so the entry idiom above was impossible. Top-level fn arity checking stays strict; loop/recur bindings remain symbol-only for now.

Behaviour change

⚠️ (seq #{}) now returns nil (Clojure parity) instead of (); (seq {}) is also nil. Two step-test assertions updated accordingly.

Notes

  • All GetSlice callers were audited (see ROADMAP-keywords.md §2, added in the first commit): the rest either gain map support with Clojure semantics or are unaffected.
  • Full test suite green; BenchmarkMAL1 unchanged within noise.
  • New tests in seqable_hashmap_test.go compare multi-entry results order-insensitively.

🤖 Generated with Claude Code

jig and others added 2 commits July 24, 2026 11:35
Study for replacing the U+029E-prefixed-string keyword representation
with a dedicated Go type, including confirmed correctness bugs, design
options and benchmarks, a migration plan targeting 0.4, and the spec
for seqable hash-maps and sets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ring

Hash-maps seq as sorted [key value] entry vectors and sets as their
sorted elements, via a single choke point in types.GetSlice (plus
ConvertFrom for vec and a seq case for Clojure parity: seq of an empty
map or set is nil). This makes seq, first, rest, map, filter, reduce,
apply, cons, concat, vec, into and lazy-seqs work over both, enabling
(into {} (map (fn [[k v]] ...) m)).

The order is sorted rather than left unspecified because first and
rest each seq the collection independently: with Go's per-call
randomised map iteration, a first/rest traversal would drop or repeat
entries. nth rejects maps and sets explicitly (they seq but are not
indexed; Clojure errors too).

Binding forms gain sequential destructuring, which the entry idiom
requires and the language lacked: vector patterns in fn params and let
bindings bind positionally and recursively, missing elements bind nil,
& binds the remainder as a list. Top-level fn arity stays strict;
loop/recur bindings remain symbol-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jig
jig merged commit 30349af into develop Jul 24, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant