From d38402eb57a3ac7cbfb10c687ca472a4a16bba27 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 17:38:48 -0400 Subject: [PATCH] algo.monads: a seq reports IPersistentList for protocol dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit algo.monads' writer monad extends a protocol to clojure.lang.IPersistentList, but jolt's lists only reported ASeq/ISeq in value-host-tags, so writer-m-add didn't dispatch ("No method writer-m-add"). jolt models every seq as a list (no distinct LazySeq — (class (map inc xs)) is PersistentList), so a seq now also reports PersistentList / IPersistentList / IPersistentStack, in value-host-tags and host-type-set. extend-protocol clojure.lang.IPersistentList then dispatches on a list. algo.monads passes its whole suite (11/11) over tools.macro. Listed in docs + site. Runtime only, no re-mint. make test green (+1 corpus row, 0 new divergences), shakesmoke byte-identical. --- docs/libraries.md | 3 +++ host/chez/records.ss | 6 +++++- test/chez/corpus.edn | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/libraries.md b/docs/libraries.md index 68f9638..1b9f319 100644 --- a/docs/libraries.md +++ b/docs/libraries.md @@ -67,6 +67,9 @@ e.g. the [ring-app example](https://github.com/jolt-lang/examples/tree/main/ring maps (incl. keyfn / custom comparator), with `subseq`/`rsubseq`. * [tools.macro](https://github.com/clojure/tools.macro) — local macros (`macrolet`/`symbol-macrolet`), `mexpand`/`mexpand-all`. +* [algo.monads](https://github.com/clojure/algo.monads) — monad macros and + monads (maybe/seq/state/writer/reader/…), over + [tools.macro](https://github.com/clojure/tools.macro). * [test.check](https://github.com/clojure/test.check) — property-based testing (generators, `quick-check`, shrinking). * [tick](https://github.com/juxt/tick) — date/time over Jolt's `java.time`; diff --git a/host/chez/records.ss b/host/chez/records.ss index 5bebf0b..7be2c04 100644 --- a/host/chez/records.ss +++ b/host/chez/records.ss @@ -480,7 +480,10 @@ ((pmap? obj) '("PersistentArrayMap" "APersistentMap" "IPersistentMap" "Associative" "Map" "java.util.Map" "Iterable" "java.lang.Iterable" "Object")) ((pset? obj) '("PersistentHashSet" "APersistentSet" "IPersistentSet" "Set" "java.util.Set" "Collection" "Iterable" "java.lang.Iterable" "Object")) - ((or (cseq? obj) (empty-list-t? obj)) '("ASeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object")) + ;; jolt models every seq as a list (no distinct LazySeq), so a seq also + ;; reports PersistentList / IPersistentList / IPersistentStack — extend-protocol + ;; clojure.lang.IPersistentList (algo.monads' writer monad) dispatches on one. + ((or (cseq? obj) (empty-list-t? obj)) '("PersistentList" "IPersistentList" "IPersistentStack" "ASeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object")) ;; a var is clojure.lang.Var (also IDeref / IFn) — reitit's Expand protocol ;; extends to Var so a #'handler route dispatches. ((var-cell? obj) '("Var" "clojure.lang.Var" "IDeref" "IFn" "Object")) @@ -626,6 +629,7 @@ "PersistentArrayMap" "APersistentMap" "IPersistentMap" "PersistentHashSet" "APersistentSet" "IPersistentSet" "ASeq" "ISeq" "IPersistentCollection" "Associative" "Sequential" + "PersistentList" "IPersistentList" "IPersistentStack" "Map" "java.util.Map" "List" "java.util.List" "Set" "java.util.Set" "Collection" "java.util.Collection" "Iterable" "java.lang.Iterable" "UUID" "BigDecimal" "Date" "Timestamp" "Instant" "java.sql.Date" diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 0ef8db2..6198407 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3380,4 +3380,5 @@ {:suite "numbers / ^long is 64-bit" :label "^long quot on a full-width long" :expected "3074457345618258602" :actual "((fn* ([^long a] (quot a 3))) 9223372036854775807)"} {:suite "host-interop / Compiler" :label "Compiler/specials keys include the special forms" :expected "true" :actual "(every? (set (keys clojure.lang.Compiler/specials)) (quote [if do let* fn* quote def loop* recur try letfn* var]))"} {:suite "macros / letfn mutual recursion" :label "letfn binds mutually-recursive named fns" :expected "[true false]" :actual "(letfn [(ev? [n] (if (zero? n) true (od? (dec n)))) (od? [n] (if (zero? n) false (ev? (dec n))))] [(ev? 10) (ev? 7)])"} + {:suite "host-interop / extend-protocol IPersistentList" :label "a protocol extended to IPersistentList dispatches on a list, not a vector" :expected "[:list :vec :list]" :actual "(do (defprotocol PL (m [x])) (extend-protocol PL clojure.lang.IPersistentList (m [_] :list) clojure.lang.IPersistentVector (m [_] :vec)) [(m (list 1 2)) (m [1 2]) (m ())])"} ]