Fork me on GitHub
Maxime D02:07:36

Hi, another very very 101 question: if you do not use Leiningen, what do you use and why?


I switched 1.5 years ago for these reasons • data-centric configuration that can be linted with clj-kondo • only runs 1 jvm • much less hidden magic, I understand what is going on much more • can create very specific project configuration very easily • run specific functions in a namespace, so not tied to clojure.main • flexible command line options I value using Clojure CLI tools I maintain a user-level configuration at that defines a wide range of tasks

💯 2
👍 2

never used lein because i never understood it


The Clojure CLI (and deps.edn) -- because it is the "official" tooling from the Clojure core team.

👍 2

The longer answer: we started out with Leiningen at work back in 2010/2011 because it was the only option but we got frustrated with the difficulty of programming/extending it so we switched to Boot (back in 2015) because build tasks were just Clojure functions. We liked that a lot but eventually ran into bugs with some of the more esoteric aspects of Boot, so in 2018 we switched to the (then very new) Clojure CLI and deps.edn and that was nice and simple -- and has continued to evolve, and soon we'll get which is quite Boot-like in some ways but also much simpler and cleaner.


Does that help @maxime? I've blogged about our changes at over the years. We have a monorepo with over 100K lines of Clojure at this point.

🙌 4
Maxime D02:07:30

Hi @seancorfield Yes that helps a lot. Trying to onboard in Clojure World and the tooling seems scattered all over the place (just a first impression, not saying it is true)


I guess it depends where you're coming from. In Java, some people use Maven others Gradle, and in JS there's a dozen of them. Clojure has three: Leiningen, Boot and tools.deps. I'd say Boot has fallen mostly out of favor, so the common choice with the best support will be lein and tools.deps. The former is older and so has more features and support, the latter is the new kid on the block, it'll probably become defacto, since it comes with Clojure itself.

💡 2

Now, if you're also doing ClojureScript, you might get confused, but think of it almost as a separate language that happens to share 95% of its syntax and common libraries between the two. So in that sense, it has its own tools as well, such as shadow-cljs or figwheel-main

Maxime D02:07:41

Looking forward to learning much much more.


Hello, I'm trying to use destructuring in compojure like I have the path ...

(GET "/foobar" [x y z]
  (str x ", " y ", " z))
But accessing http://localhost:8888/foobar?x=foo&amp;y=bar&amp;z=baz just gives me ,, I don't quite understand what could possibly be wrong especially since I have no issues with
(GET "/user/:id" [id]
  (str "The user ID is " id))


Okay i did a minimal example and it worked ..... now to figure out what i did differently in my actual project ...

Ar Nazeh08:07:17

Is there a way for ClojureScript libraries to provide a "10 secondes to demo" experience as enjoyed by JS libraries through ?


figwheel-main and GitHub with your favorite editor - or using Calva and VS Code Live Edit - seems just the same functionality with various amounts of polish or setup? I probably dont understand your point though... do you want a completely hosted environment or is it more a focus on providing features for developing web apps ?

Ar Nazeh13:07:37

No just a quick hello world demo links like this from zustand


The website you refer to seems to be a hosted environment / service that renders JavaScript, also allowing editing and live updates. Someone could build a web interface like this for ClojureScript if they thought it useful. It is what figwheel-main and shadow-cljs do, but without being contained in a hosted web application. There are already tools like Klipse to live evaluate ClojureScript code in a browser.

🙏 3

Is there a recommended starter project for full stack Clojure web development, including CLJS and some kind of React wrapper?

Pavel Klavík13:07:11

You can check out Luminus template:

👀 3
Pavel Klavík13:07:49

If you are unfamiliar with the stack, it might be better to start with only frontend or only backend in the beginning.

Pavel Klavík13:07:32

I can recommend Reagent (React wrapper) and Re-frame for the frontend.


Building front-ends with reagent (react wrapper) and figwheel-main is very simple and straight forward.


Thanks for the pointer to Web Development With Clojure. I just bought a copy of the beta. I really hope I find some time to get into it. I want to see how out of date my Clojure web development knowledge is (probably a lot at this point!)

Mitul Shah16:07:49

Would the equivalent of

:toastOptions {:className "bg-dark"}

Mitul Shah16:07:32

bcus it’s not working for me, so i must be doing something wrong


in what context? I assume this is cljs using some framework?


that looks right to me, but you might want to try #reagent


and more context around it would likely help


anybody ever seen an ls long listing like this (Mac OS X)? -rw-r--r--@ that @ at the end is a mystery to me. My clojure program crashes on reading it, even though perms look good. Cannot open <nil> as a Reader.


it’s not a symbolic link, it’s not the sticky bit or any other {g,s}UIDs (not that any of that should matter)


I did not create the file, received it from a friend’s Google Cloud bucket


wow, thanks. my googling was weak i guess.

tschady18:07:42 seems suspicious 🙂


xattr -d filename


it was from a downloaded .tgz file, not unreasonable


Well I’ll be, as my grandmother likes to say. I never did know what that @ symbol meant in ls. Thanks!

Bill O'Brien19:07:10

I have a question about implementing a cumulative sum function (my attempt is below). I feel like it should be done in one pass using reduce, but I'm not sure how to track the running sum after each item. Would I need to use an atom?

(def dat [{:obs 1 :val 2}
	    {:obs 2 :val 3}
	    {:obs 3 :val 5}])

  (defn cumulative-sum [coll val new-key]
    (as-> coll x
      (map val x)
      (reductions + x)
      (map #(assoc %1 new-key %2) coll x)))

  (clojure.pprint/print-table (cumulative-sum dat :val :cum-sum))

: | :obs | :val | :cum-sum |
: |------+------+----------|
: |    1 |    2 |        2 |
: |    2 |    3 |        5 |
: |    3 |    5 |       10 |


Not the prettiest, but definitely possible with reduce sans atom.


Now that we are here... What if one wanted to return as soon as cumulative-sum reached a certain total (e.g. you can take any number of any kind of candy, but you can only take at most N candies in total)? Enter reduced :-)

Alex Miller (Clojure team)19:07:49

loop/recur would work too

👍 2
Karen Liu20:07:23

Hello! I have a structure that's a sequence of vectors of maps, and I'm trying to filter each vector to contain only the maps that have a certain keyword. I'm still new to Clojure, so I'm having trouble envisioning how to apply the same filter across all the vectors. I've tried approaching it like (apply my-filter coll), where my-filter is a filter function that I wrote using (partial ...), but then I realized that my-filter needs to take my filtering function as its first argument because partial would force me to set a default collection within my-filter, which I don't want since I need my collection to be variable and my filtering function to be default. Is there a simpler way to do what I'm trying to do?


If you have a sequence of vectors, it sounds like you want to map over that, and the function you want to map would be a filter over each vector, and the condition would use contains? on the hash maps?


(map (partial filter #(contains? % :the-key)) coll)


user=> (def coll [ [{:a 1} {:b 2} {:c 3}] [{:a 4 :b 5} {:b 6}] [{:c 7} {:a 8}] ])
user=> (map (partial filter #(contains? % :b)) coll)
(({:b 2}) ({:a 4, :b 5} {:b 6}) ())
Is that what you're looking for @klliu23?

🙌 2
Karen Liu22:07:01

Yes! This is exactly what I was hoping to do. Thank you so much!


@klliu23 riffing off Sean's answer. In the beginning, my conceptual difficulty was rooted in trying to think of collection-in-collection as a single unit, and then try to come up with a composite function that could process the unit as a whole. It helps to flip the model and ask: ;;; --- bottom level --- smallest unit of abstraction --- • Well, what's the very smallest unit of processing? • Can I write a function for that? ;;;; --- abstraction boundary ---- • Ok, now what if I have a collection of the kind? ◦ Can I use the earlier function to map/filter/reduce over that? ◦ Can this now also become a function on a unit (where the unit is now a collection)? ;;;; --- abstraction boundary ---- • Now what if there are collections of the collection? ◦ I have a function over the "lower" level unit (which happens to be a collection). ◦ Can I use the earlier function to map/filter/reduce over the new level of collection-in-collection? One's REPL experiments and test cases fall out of that line of questioning.

❤️ 7