Fork me on GitHub

hi, I just re-discovered Clojure and I'm very excited to start learning. What resources do you recommend ? I have 10+ years coding and I'm proficient in Java and JavaScript


Make sure you setup your dev env properly before you start 🙂


Thanks. Could you be more specific? I've already built a simple clojure native application with GraalVM and also started this - using clojurephant


That's impressive


I would recommend you do the following: Read through 1 Then read through Then read through Now start referring to the Cheatsheet and  and  for all other things Finally, read through guides here Now go to and go through the exercises, start with elementary and easy. Even better, get the Android app, so you can practice on the go, the bus, the bathroom. Also for some reason the order of exercise in the Android app is the best, so I'd try and follow that. You don't need to go through them all, you can probably stop after easy or medium. Once that's done, get Clojure Cookbook and go through the recipes. Oh and, always go to the Clojure slack beginner channel and don't hesitate to ask questions and for help. Maybe always have it open in a tab:


If you have the budget for a book or two, I would recommend "Programming Clojure, 3rd ed." as one:


thank you everyone

Endre Bakken Stovner07:04:36

I like Python-style string formatting, like "hello {name}".format(name=name) . Is there a way to do something similar in Clojure? For that simple example you can just use core/str, but for complex strings with multiple variables, where some are reused, str becomes hard to read. Same with the C-style formatting from java.


If you're looking for named args specifically, I don't think there's anything built in. You could use a templating language like Selmer for this (

Endre Bakken Stovner07:04:57

But if I have lots of small strings to interpolate, it sounds like it would be slow. I should check it out though, thanks!


In core, you also have and; with the caveats that they won't work in CLJC and aren't exactly what you asked for; but definitely more powerful than just (str ...)

Endre Bakken Stovner07:04:55

Yeah, format is variadic and too hard for me to get right XD Thanks for cl-format, sounds like something I should read up on.


cl-format is a DSL beast. You may want to read up on it via some common lisp docs (e.g. and probably want to hide the line-noise DSL behind a function with good docstring of expected output. 😄

👍 4

#TIL: cljs.pprint/cl-format does indeed exist!

Patryk Wilson07:04:52

I've got two questions myself. Do I need to use Maven with clojure or can i skimp by without it? My Second questions is; I'm running CLI with tool.deps I believe and it will not let me use Ctrl+D to exit out of clojure


I'm using - via gradle because I would like to have multi language components in there


but I'm more familiar with gradle/Java then leiningen / clojure

Patryk Wilson07:04:34

Hm. I might give this a try later but atm I think I'll stick to what I have currently unless I set up something incorrectly. Appreciate it though


Hum, you shouldn't need Maven no


You can use lein, boot or tools.deps in its place


Ctrl+D should exit the deps repl, but only if there is nothing typed in the current line


You can also try Ctrl+C sometimes that does it


hi there, does anyone know how I can generate all the dates between two LocalDate instances ? I'm trying it like this

(defn months-between
  "Months between dates. Generates a sequence of java.time.LocalDate s for a given period"
  [startDate endDate]
  (take-while (fn [aDate] (.isBefore endDate aDate)) (iterate (.plusMonths startDate 1) startDate)))
end of course it fails
Execution error (ClassCastException) at netdava-internal-reporting.core/months-between (core.clj:4).
class java.time.LocalDate cannot be cast to class clojure.lang.IFn (java.time.LocalDate is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')


iterate takes a function


Your error says you are trying to use a LocalDate as if it were a function, and that doesn't work because LocalDate is not a function. That's because (.plusMonths startDate 1) returns a LocalDate, but iterate expects the first argument to be a function


got it, thanks

(defn months-between
  "Months between dates. Generates a sequence of java.time.LocalDate s for a given period"
  [startDate endDate]
  (take-while (fn [aDate] (.isAfter endDate aDate)) (iterate (fn [x] (.plusMonths x 1) ) startDate)))


this functional style takes some time getting used to


You can also do: (iterate #(.plusMonths % 1) startDate) using the anonymous function literal #()


ya, it does

Nathan K08:04:01

How would you recommend I get the behaviour of interleave, but with the interwoven collection having length 1 less than the the primary collection? I want to achieve the following:

(def grouped-thousands [34 758])
(def qualifiers ["thousand" "million" "billion" "trillion"])
(my-nifty-interleave-fn grouped-thousands qualifiers)
=> (34 "thousand" 758)
Interleave gives me this, which makes sense:
(interleave grouped-thousands qualifiers)
=> (34 "thousand" 758 "million")


I would just use butlast. EDIT: I meant use butlast after interleaving, not before.


how is that true? how is it supposed to work with e.g. [12 345 768] ?

Nathan K08:04:12

yeah never mind that 😛


you probably need 1) prepend something (`nil` ) to your qualifiers, 2) reverse your grouped-thousands before interleave , 3) reverse the result, and drop the first element of it edit: or, rather, 3) drop the first, then reverse, or something


OT: since I literally just brought up cl-format in a different thread, I've got to mention this one liner if you're interested in just having this work (and not just "solving a puzzle").

user=> (clojure.pprint/cl-format nil "~r" 12345768)
"twelve million, three hundred forty-five thousand, seven hundred sixty-eight"

Nathan K08:04:23

thanks, good to know. I am in it for the puzzzle...... but man my head is hurting right now lol. guess it doesn't help that I"m learning clojure after working a full day

Nathan K08:04:15

this is an "easy" problem on lol

Alexandre Grison08:04:59

Try with:

(-> grouped-thousands
    (interleave qualifiers)

Nathan K08:04:00

(defn say-big-number
  (let [words (->> num
                   (map say-hundreds))
        interwoven (interleave words thousands-qualifiers)
        to-english (->> interwoven
                        (join " "))]
🤯 this works... (uses some other functions)


You are solving "Say" on exercism, aren't you? There is an #exercism channel as well, 🙂

Nathan K08:04:56

good to know ! 🙂


Hi there, I have a question: in the clojure repl, I can get doc by invoking doc macro user=> (doc pr) ------------------------- clojure.core/pr ([] [x] [x & more]) Prints the object(s) to the output stream that is the current value of *out*. Prints the object(s), separated by spaces if there is more than one. By default, pr and prn print in a way that objects can be read by the reader nil but I cannot use it like this: user=> (doseq [f [pr pr-str]] (doc f)) nil why is that? how can I change this?


doc is a macro, and it is written in such a way that it does not evaluate its argument.


This might be close to what you want: (doseq [f '[pr pr-str]] (#'clojure.repl/print-doc (meta (resolve f))))


(source doc) shows the source code of the doc macro in a REPL, and the last case shows what it does if the thing you want to show the doc string for is none of the earlier special cases.


(doseq [f '[pr pr-str]] (#'clojure.repl/print-doc (meta (resolve f)))) it is magic to me, but it works thank you!


Agreed there is some magic-like stuff there for someone new to Clojure. Happy to point you at documentation that explains what some of the pieces are, if you are curious.


Here are three steps leading up to printing the doc for one function only, pr :

user=> (resolve 'pr)
user=> (meta (resolve 'pr))
{:added "1.0", :ns #object[clojure.lang.Namespace 0x66b7550d "clojure.core"], :name pr, :file "clojure/core.clj", :column 1, :dynamic true, :line 3677, :arglists ([] [x] [x & more]), :doc "Prints the object(s) to the output stream that is the current value\n  of *out*.  Prints the object(s), separated by spaces if there is\n  more than one.  By default, pr and prn print in a way that objects\n  can be read by the reader"}
user=> (#'clojure.repl/print-doc (meta (resolve 'pr)))
([] [x] [x & more])
  Prints the object(s) to the output stream that is the current value
  of *out*.  Prints the object(s), separated by spaces if there is
  more than one.  By default, pr and prn print in a way that objects
  can be read by the reader


The #' prefix before clojure.repl/print-doc is there because it lets you use a function in another namespace (`clojure.repl` in this case) even if it is marked private, which print-doc is.

👍 8

Learned something today! Isn't that also the syntax for creating a var? In that case, vars bypass the private check?


#'foo is the same as (var foo) . It does not create a var -- it tries to resolve to an existing var.


There is probably a more precise way to describe its behavior than "bypassing the private check", but not sure if I know what that more precise way is. Good enough description for now, probably.


Thanks, that makes sense 🙂


Thank you!

Jim Newton12:04:40

I'm I using a wrong syntax to define a binary multi-method?

(defmulti typep 
  "a doc string"
  (fn [a-value type-designator]
    (if (seq? type-designator)
      (first type-designator)

(defmethod typep :sigma [_ _]

(defmethod typep :empty-set [_ _]

(defmethod typep :default [a-value a-type]
  (if (and (symbol? a-type)
           (resolve a-type)
           (class? (resolve a-type)))
    (isa? (type a-value) (resolve a-type))
    (throw (ex-info (format "invalid type designator %s" a-type)
                    {:type :invalid-type-designator
                     :a-type a-type
                     :a-value a-value

Jim Newton12:04:09

when I try to call it I get an error:

clojure-rte.core> (typep 1 :sigma)
Execution error (ArityException) at clojure-rte.core/eval38559 (form-init8934354515316755715.clj:2894).
Wrong number of args (2) passed to: clojure-rte.type/eval38515/fn--38516


@jimka.issy you're coming from a lispier lisp I take it 👀

Jim Newton12:04:26

indeed. what's the problem?


I mention it in that the 'blahp' idiom in Clojure is "blah?"

Jim Newton12:04:47

clojure is cool. just have to get use to a few things.


no worries, I'm just mentioning it while I see it before I look at the overall problem


did you have another definition of this before that you've now refined (with this being the refinement?)

Jim Newton12:04:51

yes, I used cider-undef

Jim Newton12:04:04

do I need to restart the VM?

Jim Newton12:04:52

even after I restart, I get the same error.

Jim Newton12:04:00

at least it looks the same.


I was gonna say, copy and pasted into my own repl this works


and if I recall, multimethods have issues being redefined during a session (in fact, I recall just having this same issue the other day), although I don't recall why nor if there's a simpler way to fix it without restarting your session


now, you getting the same error afterwards is definitely peculiar

Jim Newton12:04:34

yes, in the repl it works.

Jim Newton12:04:46

what's a session?

Jim Newton12:04:45

maybe its the name typep?

Jim Newton12:04:54

when I name it foo-typep it works.

Jim Newton12:04:49

If I require the namespace using :as, I still get the same error. dammit.

clojure-rte.core> (require '(clojure-rte [type :as ty]))
clojure-rte.core> (ty/typep 1 :sigma)
Execution error (ArityException) at clojure-rte.core/eval38606 (form-init8934354515316755715.clj:3208).
Wrong number of args (2) passed to: clojure-rte.type/eval38515/fn--38516

Jim Newton12:04:32

Even when I redefine the defmulti to be accept any argument list, the same error happens.

(defmulti typep 
  "a doc string
  (fn [& others]
    (let [a-value nil
          type-designator nil]

      (println (list :typep others a-value type-designator))
      (if (seq? type-designator)
        (first type-designator)


ah oh no I had more to write but I'm about to lose internet, if I disappear, that's it


yep there it goes

Jim Newton12:04:51

the error and stacktrace are pretty unhelpful.

Show: Project-Only All 
  Hide: Clojure Java REPL Tooling Duplicates  (10 frames hidden)

1. Unhandled clojure.lang.ArityException
   Wrong number of args (2) passed to:

          429  clojure.lang.AFn/throwArity
           36  clojure.lang.AFn/invoke
      233  clojure.lang.MultiFn/invoke
                      REPL: 3220  clojure-rte.core/eval38620
                      REPL: 3220  clojure-rte.core/eval38620
    7176  clojure.lang.Compiler/eval
    7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
       137  clojure.lang.RestFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
      1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  142  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
           22  clojure.lang.AFn/run
               session.clj:  171  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  170  nrepl.middleware.session/session-exec/main-loop
           22  clojure.lang.AFn/run
       832  java.lang.Thread/run

Jim Newton12:04:37

it would be great if the error message said something like, wrong number of args (2) passed to .... expecting (3), you passed: (the arg list....)

Jim Newton12:04:55

OK, if I can't use multi-methods, how can I write a function which well set an entry destructively into a globally available hash table?

Jim Newton12:04:37

sort of (my-def-method ....) I'm pretty comfortable with the macrology, just don't know how to create a global mutable resource.

Aviv Kotek12:04:22

using core.matrix how can I add/increment a specific row in my matrix? let's assume 3X3 zero matrix and would like to increment dynamically a row. (add M [1 1 1]) will do broadcasting, I can build 3X3 row+2x-empty-rows (`reshape`) and do matrices addition but is there any alternative?

Jim Newton13:04:27

If I have two functions fa and fb defined respectively in two name spaces. is there a way for me to make them mutually recursive? Or am I required to refactor my code to put them in the same namespace ?


Don't think there's anything wrong with the code you pasted; you sure you're not working with a stale repl?

(defmulti typep
  "a doc string"
  (fn [a-value type-designator]
    (if (seq? type-designator)
      (first type-designator)

(defmethod typep :sigma [_ _]

(defmethod typep :empty-set [_ _]

user=> (typep 1 :sigma)

user=> (typep 1 :empty-set)

Jim Newton13:04:50

I've restarted the repl multiple times.

Jim Newton13:04:11

what does cider-restart do? does it restart clojure, or just restart a buffer using the same VM ?\


And a version with namespaces:

(ns user.protocol)

(defmulti typep
  "a doc string"
  (fn [a-value type-designator]
    (if (seq? type-designator)
      (first type-designator)

(ns user.sigma (:require [user.protocol :as p]))
(defmethod p/typep :sigma [_ _] true)

(ns user.empty (:require [user.protocol :as p]))
(defmethod p/typep :empty-set [_ _] false)

(ns user (:require [user.protocol :as p]
user=> (p/typep 1 :sigma)
user=> (p/typep 1 :empty-set)

Jim Newton13:04:44

OK, thanks for the confirmation that I'm on the right track.

Jim Newton13:04:59

I'm really puzzled about what's wrong.


cider-restart just reconnects; I think you want sesman-restart


if unsure, m-x cider-quit or C-c C-q and then cider-jack-in again

Jim Newton13:04:47

great to know.

Jim Newton13:04:35

works like a charm. 🙂

Jim Newton13:04:38

the corresponding slime command is arguably more understandable slime-restart-inferior-lisp

Jim Newton13:04:54

Thanks for the help, guys.


yeah. things get a bit murky due to CIDER handling multiple connections


so there's ambiguity in restarting the system or restarting CIDER's connection


not sure if slime lets you run multiple different CL's scoped to the same and different projects

Jim Newton13:04:38

well i found it unclear. restarting cider i though would restart the underlying lisp

Jim Newton13:04:56

OK, I was mistaken, and I know now.

Jim Newton13:04:57

I'm not sure what the corresponding concept of project is for slime. but yes you can have multiple repls in the same slime session which are all connected to the same inferior lisp.

Jim Newton13:04:32

I doubt slime supports running multiple inferior lisps simultaneously.

Jim Newton13:04:29

when I started using Scala a couple of years ago, the concept of project was really difficult to grasp.

Jim Newton13:04:07

I was attempting to do this with mutimethods, and just define each method in the namespace where its dependencies are visible. but I couldn't get that to work. see message above...

Vincent Cantin15:04:55

I am looking for a predicate (or a composition of predicates) which could test if a collection is at the same time seqable? and has a deterministic result order when passed to seq (excluding the sets collections, for example). Does it exist somewhere in a dark corner of the standard library, or should I just test if it is not a set ?

Vincent Cantin16:04:29

a kind of consistent-seqable? ?


all collections are seqable and many things that are not collections are seqable

👍 4

maybe you just want sequential?

🎉 4

but strings, ArrayList, etc. are seqable and ordered but not sequential?


but if you don't care about seqable, and just care about clojure native collections, sequential? is what you want

Vincent Cantin16:04:31

sequential? is exactly what I need, thanks a lot


anyone know how i can write this more elegantly? :

((if (nil? boop) #(log/infof % %2 %3) #(log/warnf % %2 %3))
     "boop [%s] beep [%s]."


What is the end goal there? To use either log/infof vs log/warnf depending if boop is nil or not?


Be careful with your use of higher order functions like that, it's an easy beginner anti-pattern which people get trapped in.


You should try to avoid higher order functions as much as possible


ah, map and reduce are higher order functions


why not just ((if boop log/warnf log/infof) <...whatever...>) ?


@U050MP39D They're not? They take a hof as an argument.


If you need to pass a hof to an existing function off course you have to use one. But if you're writing a function that takes a hof, or using hof in places that don't expect them like here, you should reconsider your approach


Unless you know better


a higher order function is a function that takes a function as an argument or returns one


map and reduce take a function as an argument


they also technically return a function when used as a transducer


and they don't take hof as arguments, too


I have no idea what @U0K064KQV could possibly mean by that "They're not?"


they could take a hof as an argument. not very usual though


the idea is just to keep repeating as little as possible. I didnt want to write an if block that has the log message twice


right, if you are reducing a collection of functions


@UV674TMLM yeah I got you. I agree with the other person though that the repeated code is far far more readable than any of the alternatives. jsn's solution is probably the most readable version without repeated code


Sorry, you guys are correct, I used the wrong terminology. I meant to say anonymous functions


For which a function which takes or return one would be a hof


I guess my point is, don't write hof yourself unless you know better


But I guess I'm extending that to more than just hof


Just don't write code that returns or takes functions, unless you know better


well I'd quibble with that too. I think I'd prefer an anonymous function over partial in almost every case. but that's a personal preference


That includes in forms like "if"


There's just no proper name for the specific things I'm talking about :p


Anything which takes an IFn or returns an IFn


that is a HOF but that includes map/reduce 😛


Don't write such thing, unless you've explored alternatives first and deemed them to be worse


Maybe just a HO without the F ?


(if true #(identity 10))


That's just a form


No functions here, but it returns a function


Higher order form maybe?


Honestly, I would just write

(let [fmt "boop [%s] beep [%s]."]
  (if boop
    (log/warnf fmt boop beep)
    (log/infof fmt boop beep)))

👍 16

I learned recently that you can pass a log level to log/logf like this:

(let [fmt "boop [%s] beep [%s]."]
  (log/logf (if boop :warn :info) fmt boop beep))


could also just be

(log/logf (if boop :warn :info) "boop [%s] beep [%s]." boop beep)


thats great thanks nate!


you're welcome, glad to help


To me, that looks a lot easier to maintain later on.


It’s possible to be too DRY.

ryan echternacht18:04:16

Clojure embraces the bazaar mentality to ecosystem management, which is powerful, but has the drawback of making it hard to get a lay of the land (especially for beginners). What are the best resources to get “best practices” when it comes to tech stacks?


@ryan072 That's a bit too open-ended to answer I think. And you'll get different answers from different folks even if you narrow the focus a bit.


Are you talking about web development? Data science? Front end? Back end? Command-line utilities? Server processes?

ryan echternacht18:04:53

honestly, a bit of everything. i guess im asking what “maps” exist they have decent coverage/agreement


You should assume that they all have equal coverage/agreement. Like every lib or framework has equal mindshare. Hopefully that will get you over the OCD of looking to use the "most popular" option by seeing that all options are equally valid in Clojure and are equally being used


Once you get over that hump, which is often there because of your own lack of confidence in being able to judge, so assume that they're all good and worthy of being used, then just choose the one you prefer or like the sound of.

ryan echternacht01:04:08

@U0K064KQV I see where you’re coming from, but there are distinct advantages to using “the most” used tools — i.e. better documentation, ongoing development, etc. Was more curious, but this seems to be the biggest issue with a “bazaar” mentality. To be clear, I feel the benefits outweigh the costs long term, but that doesn’t mean the drawback disappears.


But if all options have good documentation and ongoing development?


Because that's the case for a lot of things in Clojure


It's not like there's a bunch of abandoned options. The bazaar means there's a bunch of options all used in production by different people

ryan echternacht18:04:05

there are times when i feel like “someone’s blog said X” is the best I have to go off of


I don't think any such things exist for Clojure. I've seen folks ask about "learning maps" in the past and don't recall them getting a useful answer.


i use as a reference sometimes, but I still have to evaluate the options enumerated

❤️ 4

so, if I want to use the features in my editor (neovim) that are the most important to 99.99% clojure(script) developers (the REPL), I need to use python (wtf), and cider, which is something for emacs? Is that correct?


that's what I disliked in vim as well. Python dependency, even ruby(for the stack that I used). I've switched to emacs ~ 1 year ago(spacemacs in evil mode to be exact) and I wish I made that switch much earlier.


To answer your question - yes, you need cider for repl access in clojure.


If you're considering a possibility of switching to emacs - FYI: it took me a few days before I felt as productive as I was in vim. It's not that difficult. Evil mode = basically the same exact vim shortcuts but in emacs.


thanks, I like spacemacs very much, but just for one language I can't pick it up, and my other language, javascript, well, very long and frustration story, tl;dr is that I could never configure it for my liking


Don't know if it also depends on Python, but I think it offers a much better experience then fireplace


Oh, the doc says: No python


So there ya go, just switch to it


Also, not all of Cider is specific to Emacs. So a lot of it is used by other editor.


Mostly cider-nrepl


I am talking about fireplace which is the only option afaik


only 9% of clojure developers use vim as their primary editor for clojure, so it may be a little rough around the edges

☝️ 4

and then clojurescript is the less-widespread clojure


is that a yes to my question? 🙂


haha, sorry. my actual answer is I don't know.

👍 4

possibly asking in the clojurescript or vim channels might get you better help than me


those are for professional clojure(script) developers 🙂

😕 4

Fireplace is not the only option. There is


But I have no experience with either.


@hindol.adhya I asked the author of Conjure today and I might've misunderstood but I think he said it was not compatible yet, or not fully, but very soon it's possible that it will be another option


You want to use Vim or NeoVim?


Yes, I saw that, but to my understanding Conjure is written for NeoVim. It might have compatibility issues with Vim but unlikely for NeoVim.


hopefully, you won’t have to write python code. I think that’s just the language neovim plugins are written in.


I do not even want to use python


I have enough trouble with it elsewhere (at work) and in no way I want to deal with all their issues constantly because my dev-env depends on them


@hindol.adhya who said that conjure has compatibility issues with neovim?


That's what I understood from your comment just before this thread.


But clearly, you meant something else.


Why would I say something that stupid?


As you yourself pointed out, it is written for neovim...


there’s no need for name calling. especially since @hindol.adhya is trying to help


what name calling? 🙂


> Why would I say something that stupid? this isn’t technically name-calling, but it’s being antagonistic. we’re here to help!


I believe fireplace works with nrepl (rather than cider). nrepl has good integration with emacs, but it’s used by many other ide plugins as well


I am grateful for any help. Misrepresenting my statement and diverting the discussion however is not helpful, I hope I am allowed to state the obvious 🙂


the idea with fireplace, is that you install the plugin, but you won’t have to write/read any python


are you looking for interactive repl or just a repl in general?


@smith.adriane I it says in the docs that > First, set up (If you skip this step, only a subset of functionality will be available.) I am using an app generated with It works fine, using devcards even, but would like to have autocompletion in my editor


do you have a link to the docs you’re using?


I am sorry, I don't quite understand the question


I couldn’t find where this quote is from: > First, set up (If you skip this step, only a subset of functionality will be available.)


is that at create-cljs-app?


the two pieces for emacs cider to work well are an emacs plugin (also called cider) and an nrepl server. it turns out the nrepl server can also be used by other ide’s (which fireplace takes advantage of)


much of the documentation is tailored towards the most common workflow(emacs + cider/nrepl)


oh, so it's just cider in name only


from cider-nrepl link > A collection of middleware originally designed to enhance


ok, I started trying vim-iced when I found it, but if it doesn't work out I will try fireplace, thank you very much @smith.adriane for clearing the confusion

👍 4