erlang: lists keylist BIFs (keyfind/keymember/keydelete/keyreplace/keystore/keytake/keysort) (809/809)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m3s

Adds the tuple-keyed list family to lib/erlang/lists-ext.sx: act on
first match, key compare via == (er-equal?), non-tuples/short tuples
pass through. keysort/2 reuses the stable merge sort + full term
order. keytake/3 returns {value, Tuple, Rest} | false. All seven
registered through the er-register-builtin-bifs! wrapper so they
survive mid-run registry resets. lists_ext suite 17 -> 38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-30 13:28:57 +00:00
parent 355a482dfe
commit 343c508939
5 changed files with 203 additions and 6 deletions

View File

@@ -141,6 +141,114 @@
(er-ext-dedup
(er-ext-msort (er-cons->sxlist lst) er-ext-term-le))))))
;; ── keylists (lists of tuples keyed on element N, 1-indexed) ──────
;; keyfind/keymember/keydelete/keyreplace/keystore/keytake/keysort.
;; Key comparison is == (er-equal?), matching the standard lib. Only
;; the FIRST matching tuple is acted on. Non-tuples / tuples shorter
;; than N never match and are passed through unchanged.
(define
er-ext-tup-elem
(fn (tup n)
(if (er-tuple? tup)
(let ((es (get tup :elements)))
(if (and (>= n 1) (<= n (len es))) (nth es (- n 1)) nil))
nil)))
(define
er-ext-key-match?
(fn (key n tup)
(and
(er-tuple? tup)
(>= n 1)
(<= n (len (get tup :elements)))
(er-equal? key (nth (get tup :elements) (- n 1))))))
(define
er-ext-keyfind
(fn (key n lst)
(cond
(er-nil? lst) (er-mk-atom "false")
(er-cons? lst)
(if (er-ext-key-match? key n (get lst :head))
(get lst :head)
(er-ext-keyfind key n (get lst :tail)))
:else (er-mk-atom "false"))))
(define
er-ext-keydelete
(fn (key n lst)
(cond
(er-nil? lst) (er-mk-nil)
(er-cons? lst)
(if (er-ext-key-match? key n (get lst :head))
(get lst :tail)
(er-mk-cons (get lst :head) (er-ext-keydelete key n (get lst :tail))))
:else lst)))
(define
er-ext-keyreplace
(fn (key n lst new)
(cond
(er-nil? lst) (er-mk-nil)
(er-cons? lst)
(if (er-ext-key-match? key n (get lst :head))
(er-mk-cons new (get lst :tail))
(er-mk-cons (get lst :head) (er-ext-keyreplace key n (get lst :tail) new)))
:else lst)))
(define
er-ext-keystore
(fn (key n lst new)
(cond
(er-nil? lst) (er-mk-cons new (er-mk-nil))
(er-cons? lst)
(if (er-ext-key-match? key n (get lst :head))
(er-mk-cons new (get lst :tail))
(er-mk-cons (get lst :head) (er-ext-keystore key n (get lst :tail) new)))
:else lst)))
(define
er-bif-lists-keyfind
(fn (vs) (er-ext-keyfind (nth vs 0) (nth vs 1) (nth vs 2))))
(define
er-bif-lists-keymember
(fn (vs)
(er-bool (not (er-atom? (er-ext-keyfind (nth vs 0) (nth vs 1) (nth vs 2)))))))
(define
er-bif-lists-keydelete
(fn (vs) (er-ext-keydelete (nth vs 0) (nth vs 1) (nth vs 2))))
(define
er-bif-lists-keyreplace
(fn (vs) (er-ext-keyreplace (nth vs 0) (nth vs 1) (nth vs 2) (nth vs 3))))
(define
er-bif-lists-keystore
(fn (vs) (er-ext-keystore (nth vs 0) (nth vs 1) (nth vs 2) (nth vs 3))))
(define
er-bif-lists-keytake
(fn (vs)
(let ((key (nth vs 0)) (n (nth vs 1)) (lst (nth vs 2)))
(let ((hit (er-ext-keyfind key n lst)))
(if (er-atom? hit)
(er-mk-atom "false")
(er-mk-tuple
(list (er-mk-atom "value") hit (er-ext-keydelete key n lst))))))))
(define
er-bif-lists-keysort
(fn (vs)
(let ((n (nth vs 0)) (lst (nth vs 1)))
(er-sxlist->cons
(er-ext-msort
(er-cons->sxlist lst)
(fn (a b)
(er-bool
(not (er-ext-lt? (er-ext-tup-elem b n) (er-ext-tup-elem a n))))))))))
;; ── register ──────────────────────────────────────────────────────
;; Hook into er-register-builtin-bifs! rather than registering once:
;; the registry can be reset + rebuilt mid-run (tests/runtime.sx does
@@ -150,7 +258,14 @@
(fn ()
(er-register-pure-bif! "lists" "sort" 1 er-bif-lists-sort)
(er-register-pure-bif! "lists" "sort" 2 er-bif-lists-sort)
(er-register-pure-bif! "lists" "usort" 1 er-bif-lists-usort)))
(er-register-pure-bif! "lists" "usort" 1 er-bif-lists-usort)
(er-register-pure-bif! "lists" "keyfind" 3 er-bif-lists-keyfind)
(er-register-pure-bif! "lists" "keymember" 3 er-bif-lists-keymember)
(er-register-pure-bif! "lists" "keydelete" 3 er-bif-lists-keydelete)
(er-register-pure-bif! "lists" "keyreplace" 4 er-bif-lists-keyreplace)
(er-register-pure-bif! "lists" "keystore" 4 er-bif-lists-keystore)
(er-register-pure-bif! "lists" "keytake" 3 er-bif-lists-keytake)
(er-register-pure-bif! "lists" "keysort" 2 er-bif-lists-keysort)))
(define er-ext-prev-register-builtins er-register-builtin-bifs!)
(define er-register-builtin-bifs!