This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-23
Channels
- # announcements (18)
- # beginners (26)
- # calva (12)
- # cider (43)
- # cljdoc (4)
- # clojure (38)
- # clojure-europe (11)
- # clojure-nl (1)
- # clojure-norway (12)
- # clojure-sweden (2)
- # clojure-uk (4)
- # cursive (17)
- # data-science (4)
- # datalevin (2)
- # datomic (3)
- # emacs (10)
- # ghostwheel (4)
- # graphql (11)
- # honeysql (1)
- # hyperfiddle (7)
- # introduce-yourself (1)
- # malli (23)
- # nrepl (11)
- # overtone (1)
- # pathom (9)
- # pedestal (2)
- # polylith (1)
- # portal (3)
- # reitit (1)
- # shadow-cljs (12)
- # timbre (4)
- # vim (2)
- # xtdb (4)
Wondering a good way to group sets of form (x form)+
in a sequence where x is a particular symbol.
Let's say x is '$
.
I want to turn this:
'(a b c $ d e $ f $ g $ h i $)
into:
'(a b '(c $ d) '(e $ f $ g $ h) i $)
I've written that a couple times.
Was looking for something more quick and dirty for this specific case
I only really care about that particular symbol at the moment
I'm not sure any sequence of forms would convert nicely to rpn
I'm gonna try using a couple take-while
s
This is a fun start:
(defn regroup [xs]
(loop [xs xs
ys []
zs []]
(if (< (count xs) 3)
(if (empty? zs)
(concat ys xs)
(concat ys [zs] xs))
(let [[x y] xs]
(if (empty? zs)
(if (= '$ y)
(recur (drop 1 xs) ys [x])
(recur (drop 1 xs) (conj ys x) []))
(if (= '$ x)
(recur (drop 2 xs) ys (conj zs x y))
(recur xs (conj ys zs) [])))))))
(regroup '(a b $ c $ d e $ f g))
;=> (a [b $ c $ d] [e $ f] g)
but doesn't work for all cases yet, and I'm at eod...If there are any takers I'll add that the input sequence won't have any nil values.
I just realized that and likely offers some better solutions.
Would clojure.spec (or Malli?) be an option?
(require '[clojure.spec.alpha :as spec])
(spec/def ::data (->> (spec/cat :dollar #{'$}
:value any?)
spec/*
(spec/cat :first any? :rest)
spec/*))
(->> '(a b c $ d e $ f $ g $ h i $)
(spec/conform ::data)
(mapcat (fn [{:keys [first rest]}]
(if rest
[(into [first] (mapcat (juxt :dollar :value)) rest)]
[first]))))
;; => (a b [c $ d] [e $ f $ g $ h] i $)
Slightly shorter, and less nested version of yours @U05H8N9V0HZ. It works on your example input, not sure about others:
(defn- conj-seq [coll x & xs] (apply conj (cond-> coll (seq x) (conj x)) xs))
(defn regroup [sep coll]
(loop [[a b c :as xs] coll, pt [], acc []]
(cond (empty? xs) (conj-seq acc pt)
(and c (= sep b)) (recur (drop 3 xs) (into [] (take 3) xs) (conj-seq acc pt))
(and b (= sep a)) (recur (drop 2 xs) (into pt (take 2) xs) acc)
:else (recur (rest xs) [] (conj-seq acc pt a)))))
(regroup '$ '(a b c $ d e $ f $ g $ h i $))
;; => [a b [c $ d] [e $ f $ g $ h] i $]
@U03JZS99P27 The spec solution looks amazing. Would be a rabbithole for me to understand it, but a rabbithole worth diving down when I have time 🙂 How costly of an import is it? I need to GraalVM compile it and it feels like something that would probably bloat up my artifact size which is a concern.
@UE1N3HAJH thanks for the effort. I was about to fix mine but I'll test yours instead and fix if needed. Will post the final here when done.
@U05H8N9V0HZ I don't know how costly the import would be. But I would also take a look at Malli:
https://github.com/metosin/malli?tab=readme-ov-file#sequence-schemas
It has similar syntax for expressing regular grammars using :altn
and :*
but I don't know Malli well enough. Malli is actively maintained so it may be a good alternative.
@UE1N3HAJH This works as expected for the test cases shown:
(defn- conj-seq [coll x & xs] (apply conj (cond-> coll (seq x) (conj x)) xs))
(def sep '$)
(defn regroup [coll]
(loop [[a b c :as xs] coll, pt [], acc []]
(cond (empty? xs) (conj-seq acc pt)
(and c (= sep b) (not= a sep) (not= c sep))
(recur (drop 3 xs) (into [] (take 3) xs) (conj-seq acc pt))
(and b (= sep a) (not (empty? pt)))
(recur (drop 2 xs) (into pt (take 2) xs) acc)
:else
(recur (rest xs) [] (conj-seq acc pt a)))))
(regroup '())
(regroup '(a))
(regroup '($))
(regroup '($ $))
(regroup '(a b))
(regroup '(a b $))
(regroup '($ b))
(regroup '(a $ $ b $))
(regroup '(a b c))
(regroup '(a b $ c $ d e $))
(regroup '(a b $ c $ d e $ f g))
(regroup '(a b $ c $ d e $ $ f g))
(regroup '($ a b $ c $ d e $ $ f $))
(regroup '($ $ a b $ c $))
Just added the (not= a sep) (not= c sep)
and (not (empty? pt))
conditions
Nice. Looks much better with the cond
rather than nested if
s to me. Have to admit though the spec-based approach does seem beautifully declarative if you can afford the deps.
Agreed on both 🙂
@U03JZS99P27 would your solution work same on those cases?
@U05H8N9V0HZ I am not totally sure about that because there could be ambiguities that Malli handle differently compared to Spec. So you have to try and see what works 🙂
@UE1N3HAJH Forgot to say that yours handled more cases than mine before I touched it. Good job!

@UE1N3HAJH Just wondering. Why is the symbol pt
?
paren-thing?
Short for partition
. In clojure.core functions that take runs, they often call it part
- sorry being a bit golfy
Looking for public input from the Clojure community: https://clojureverse.org/t/should-linux-distributions-ship-clojure-byte-compiled-aot-or-not/10595 The Linux distribution I package for is not sure if we should be byte-compiling all Clojure code, just apps and why byte compiling is different in Clojure vs Java
thanks for posting here, i'm hopeful that the Guix maintainers will be able to see reason on this
Agreed @U0HG4EHMH - that's what I thought the position would be: byte-compile an 'app', libs for developers are source distributed. The problem is that while it's obvious to those doing Clojure - I couldn't find a specific statement saying "Distributions and general package managers should not byte-compile libraries they distribute" which makes it's difficult to argue as there's no clear policy statement.
I appreciate thheller, Sean and others taking time on their Friday evening to try and shine some light :-)
@UV1JWR18U you might spark an improvement to the documentation by taking the question to http://ask.clojure.org
> I couldn't find a specific statement saying "Distributions and general package managers should not byte-compile libraries they distribute" Probably because it wouldn't occur to Clojurians that anyone would even contemplate doing this? (since we all use Maven Central and Clojars to get get our libraries)
and (which distro managers might not know) Clojure libraries on Maven Central and Clojars are not compiled
I don't really know what I'm talking about, but since it's guix and those people ought to know their lisp: think of compiled clojure code more like Common Lisp .fasl
files (which have little compatibility guarantees) instead of like Java .class
files. Just generally the loading/compiling story is a lot more like CL than like Java. Libraries are distributed as source and dynamically compiled by loading them into a language environment. AOT (and uberjars btw) is for final application distribution (rough parralels to sbcl images), not for library distribution.