jolt/.dirge/skills/jolt-persistent-structures/SKILL.md
Yogthos 053ed4f790 Phase 8: Protocol System — defprotocol, extend-type, extend-protocol, satisfies?
- types.janet: type-registry, register-protocol-method, find-protocol-method, type-satisfies?
- core.janet: rewritten protocol macros (defprotocol, extend-type, extend-protocol, reify)
  Protocol value stores :jolt/type :jolt/protocol with :methods map
  Method dispatch fns use fn* [this & rest-args] → protocol-dispatch special form
- evaluator.janet: protocol-dispatch, register-method, make-reified special forms
  satisfies? special form with type registry lookup
  special-symbol? entries for all 3 protocol ops + satisfies?
- 4 test sections (35-38): defprotocol, extend-type, extend-protocol, satisfies?
  extend-type: basic dispatch works (42 constant), .-field accessor needs further debug
  satisfies?: fully functional with type registry
- 315 ok, 2 fail (pre-existing, unchanged)
2026-06-03 00:18:41 -04:00

2.6 KiB

name description
jolt-persistent-structures PersistentHashMap, PersistentHashSet, and LazySeq implementation patterns in Janet tables

jolt-persistent-structures

PersistentHashMap, PersistentHashSet, and LazySeq implementation patterns in Janet tables.

PersistentHashMap

Bucket-based immutable hash map using copy-on-write. Stores data in :buckets (array of flat [k v k v ...] bucket arrays), :cnt (entry count), :jolt/deftype type tag, and :_meta.

Core functions (in phm.janet)

  • make-phm [& kvs] — create from key-value pairs
  • phm-get [m k &opt default] — lookup with optional default
  • phm-assoc [m k v] — return new map with k→v
  • phm-dissoc [m k] — return new map without k
  • phm-contains? [m k] — membership check
  • phm-count [m] — number of entries
  • phm-to-struct [m] — convert to Janet struct (for equality, keys, vals)
  • phm-entries [m] — return [[k v] ...] pairs

Core function integration (core.janet)

Each core fn checks phm? first, then falls through to struct/table logic:

  • core-getphm-get
  • core-assocphm-assoc
  • core-dissocphm-dissoc
  • core-contains?phm-contains?
  • core-countphm-count
  • core-keys/vals/seq → via phm-to-struct
  • core-merge/merge-with → PHM-aware iteration
  • core-empty? → check :cnt = 0
  • core-conjphm-assoc for [k v] pairs

Gotchas

  • core-map?: (if (and (table? x) (get x :jolt/deftype)) true false)and returns last truthy
  • core-count: subtract 1 for deftype tables
  • Equality: phm-to-structdeep=
  • core-hash-map wraps make-phm, so all literal maps become PHMs

PersistentHashSet

Backed by a PersistentHashMap with sentinel true values.

Core functions (in phm.janet)

  • make-phs [& xs] — create from items
  • phs-conj [s & xs] — add items (idempotent)
  • phs-disj [s & xs] — remove items
  • phs-contains? [s x] — membership
  • phs-count [s] — cardinality
  • phs-seq [s] — keys as tuple
  • phs-get [s x &opt default] — returns x if present
  • phs-to-struct [s] — convert for equality via deep=

Special forms (evaluator.janet)

  • :jolt/set handler: (apply make-phs (form :value))
  • "disj" dispatch — validates set?, calls phs-disj
  • "set?" dispatch — calls set? predicate

LazySeq

Realize-once thunk wrapper.

Core functions (in phm.janet)

  • make-lazy-seq [thunk] — create from thunk
  • realize-ls [ls] — force + cache (recursive)
  • ls-first/ls-rest/ls-seq/ls-count

Gotchas

  • Use indexed? not tuple? for realized sequences
  • Avoid val' (parse error), use vf