This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-09-04
Channels
- # announcements (1)
- # babashka (41)
- # beginners (124)
- # cider (8)
- # clj-kondo (25)
- # cljs-dev (40)
- # clojars (4)
- # clojure (92)
- # clojure-europe (35)
- # clojure-italy (3)
- # clojure-nl (4)
- # clojure-uk (91)
- # clojuredesign-podcast (8)
- # clojurescript (41)
- # code-reviews (1)
- # cursive (11)
- # data-science (1)
- # datascript (76)
- # datomic (45)
- # emacs (4)
- # etaoin (3)
- # events (1)
- # figwheel-main (2)
- # fulcro (9)
- # graalvm (1)
- # jackdaw (6)
- # jobs (1)
- # jobs-discuss (3)
- # kaocha (4)
- # malli (25)
- # off-topic (42)
- # pathom (4)
- # reitit (11)
- # releases (2)
- # reveal (1)
- # shadow-cljs (53)
- # sql (4)
- # tools-deps (190)
- # vrac (19)
- # xtdb (6)
(defn drop-both-sides
[n lst]
(drop n (drop-last n list)))
I expect this to do what the name says, take n elements off beginning and end of list.
Instead I get error about IllegalArgumentException Don't know how to create ISeq from:
clojure.lang.PersistentList$Primordial. How would I do a double take?you have lst
in the arg and list
in the code
Hi guys, I took part of a good discussion yesterday about the requirements a language should have to be considered as part of the Lisp family. In this case, they argued that LFE is not effectively Lisp, but just a language with syntax similar to Lisp, because for instance it doesn't have homoiconicity (I'm not sure about this statement). Why is it this exactly? The same rationale would apply to Clojure?
Ask in #off-topic These discussions can be pretty abstract and not good beginner fodder
should i bother with namespaced keywords? I'm guessing the answer is "it depends", but then i'm wondering what it depends on π
If you're starting a project from scratch, I would make an effort to use them and get used to them.
Sure, you have to map them to/from unqualified keywords for your API (either REST/like input and results in JSON or HTML forms and URL query params), but that's to be expected -- and no reason to avoid them inside your code.
If you're doing JDBC stuff, next.jdbc
's default is qualified keywords. Datomic uses qualified keywords. Spec is really all about qualified keywords.
They have a lot of semantic benefits, e.g., a :person/name
is different to a :product/name
, after all.
for ones with namespaces, it seems I don't actually need to declare them somehow, right? I just pretend they exist?
i just read this btw: https://vvvvalvalval.github.io/posts/clojure-key-namespacing-convention-considered-harmful.html
i agree about the pain of namespaces for things that hit the wire or go into a database. but for internal stuff it makes it quite nice to disambiguate keywords and usage. For instance, our backend sends a websocket notification message with topic :report/progress
and :report/complete
. (over the wire but we use edn so it works for us). Finding the emitters and consumers of these notifications is quite easy. if they were just :progress
and :complete
there could be hundreds of instances of these keywords. But i can quickly find these particular notions of progress and complete. His argument that "report_progress" and "report_complete" can go in a db without change is true but these are ephemeral data in motion so we don't have that issue
> things that hit the wire or go into a database
There's no problem with them going into the database: the qualifier is simply ignored (by both clojure.java.jdbc
and next.jdbc
).
With c.j.j you can get qualified keywords on things coming out of the database, but it's primitive: you can specify a simple :qualifier "prefix"
and that's it. With next.jdbc
, it tries hard to put "sensible" qualifiers on the keywords, matching the table the column comes from (very useful in a joined query).
It won't surprise you that I disagree with a lot of that article π
If our front end was ClojureScript, rather than JS, we'd probably traffic in EDN or use Transit so we could keep qualified keywords in play right from the user interface all the down to the database and back again.
along similar lines.. if you are dealing with Java objects do you sort of treat those as "over-the-wire" and turn into a common format, or just use them "as is" in your clojure code... unless of course all your code is clojure in which case moot question.
All clojure objects are equally as enfranchised as java objects
In the sense that they have an innately compatible representation as jvm bytecode
There are quite a few libraries that wrap Java libraries to make them "clojure-y"-- that's mostly for syntactical preference-- but there's no reason not to use Java objects "as is", as it is pretty straightforward.
@joel380 Since that blog post doesn't support comments (which seems to be an unfortunate trend on blogs, these days, so you can only take the posts on face value, without the benefit of an actual discussion), it might help you to read this thread about it https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169
Oh, now the comments are loading on the blog. They wouldn't load earlier so I thought there were no comments there. I know the discussion happened in multiple places.
Re: Java objects -- can you provide a bit more context @joel380?
Clojure is a hosted language that expects you to use Java interop. Not sure what "over-the-wire" would mean in that context: it's very common for Clojure code to manipulate Java objects.
I have an edn file with a map, I would like to retain the written order of that map. Is there a way to accomplish this?
You should not rely on the order of maps. If you need to represent order, use a list or vector.
1. create input stream from this file. 2. read until you hit \{ character 3. start reading the same stream via clojure.tools.reader.edn/read until you get βUnmatched delimiter }.β exception 4. already read items should have even number of items represent kvs of the map in file, just turn them into desired structure
in short, no. use an ordered coll like a vector.
Hey all. Iβm just starting out with Clojure and coming from a JS background. Iβm having a bit of trouble understanding variable scope. Hereβs an example from a Udemy course where a validCoupon
variable is defined in a function isCodeValid
and then used inside another function called getCarPrices
. You canβt do this in JS because function scope boundaries hide internals from each other. So what is happening when validCoupon
is assigned? Is that variable now available on a βglobalβ scope relative to the namespace (ie file)?
This is bad code and you should take a different course :)
def creates a global var and should only be used at the top level of your code
Is there a reason that Clojure permits creation of global variables in function scope like that?
Iβm sure thereβs some use case I havenβt thought of but Iβm not used to this being possible.
Inside a function you should use let
to create lexically scoped locals
@alexmiller Ah that makes a ton more sense. Actually, Iβm realizing a big issue with this course is that the instructor doesnβt introduce scope at all. The section on Variables talks only about immutability, valid characters, and case sensitivity but not scope.
link to course @rosschapman?
you mean βwrongβ like not conventional/anti-patterns etcβ¦ ?
If you have some place to leave feedback for this, please do :)
I wil
Any thoughts on this one? https://www.udemy.com/course/learning-clojure/
@rosschapman Here as an intro to clojure i wrote a while back. https://drewverlee.github.io/posts-output/2017-4-26-simple-by-design Beyond that. Purely functional TV and Lambda island has online classes if you like that medium
Indeed. If your learning Clojure(Script) and you like video courses: β’ lambdaisland β’ purelyfunctionaltv β’ https://www.learnreagent.com/
@rosschapman Have you seen this book? It's a good place to get started: https://www.braveclojure.com/foreword/
I havenβt! My interested was piqued after reading Zachary Tellmanβs https://elementsofclojure.com/. Which I liked for the parts that were not Clojure specific.
Also generally wanting to try something more Lisp-y.
Iβve also been reading a lot lately so thought Iβd try learning from online video/tutorials just to mix things up.
Makes sense. If you want to practice small problems, I'd recommend HackerRank. It really helped me, especially when I was itching to actually start coding (rather than just read): https://www.hackerrank.com/domains/fp
Oh cool. I noticed Code Wars also supports Clojure. Itβs really great to see other folksβ solutions to learn the syntax.
I can also highly recommend https://practicalli.github.io/
Already watching a talk now. Thanks for the rec!
https://exercism.io/ has a clojure track and you get a mentor too. You can also use the #code-reviews channel on the Clojurians slack comunity to get feedback
A really good way to practice using the core functions of Clojure is http://www.4clojure.com/
And as you are from a JavaScript background, https://www.learnreagent.com/ should be of interest (the author of the course is predominantly a JS developer professionally)
dev=> (car/wcar {:host "localhost" :port "6379"})
Execution error (ConnectException) at (Net.java:-2).
Connection refused
Anyone ever have issues connecting to redis from the repl?
For us folks trapped in json-land... Is writing clojure spec directly against the incoming json data model and generating json schema for clients from the clojure.spec effective? I'm hoping that spec can be leveraged somehow for transforming directly into clojure data down the road (whereas for now we likely use existing Java objects).
Well, you'd have to convert from JSON to keyword-based hash maps before you could apply Spec, so you could either use :req-un
/`:opt-un` on plain keywords (and later convert to whatever internal qualified-keyword domain structures you wanted) or perhaps arrange for the JSON-to-map conversion to add qualifiers and use regular Spec stuff (`:req`/`:opt`). But in Spec 2, handling of unqualified and qualified keywords diverges further due to s/schema
/`s/select` effectively replacing s/keys
.
This code leads me to believe that clojure =
does some kind of structural equality check between lists? Is that correct?
(= (list ()) (list ()))
I think you are correct. The Clojure collections are values, and thus we don't have to compare by references.
About halfway down the "Summary" section of this page explains how =
works with collections. https://clojure.org/guides/equality

Yep: βSequential collections (sequences, vectors, lists, and queues) with equal elements in the same order are equalβ
So itβs structure and value comparison
@rosschapman itβs not as much a thing in JS, but if youβre ever curious what Clojure code is doing (in the event that the docstring isnβt enough) the source is available. In this case: https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core.clj#L783 I found this increasingly helpful as I was learning the language π
If you mean by βnot as much a thingβ as in JS doesnβt have simple means of comparing objects and arrays (ie collections) youβre definitely right! Even with ===
Strict Equality Comparison it will only return true by reference. So getting βcontentβ or structural comparison is trickier.
So it looks like =
implements clojure.lang.Util/equiv
under the hood which is referenced here (I think?): https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Util.java#L24. Thereby implementing both Javaβs ==
and equals()
check. And Iβm assuming comparing lists falls through to line 33 where equals()
is called because the ==
check on lin 25 fails for checking by reference, and then the other conditions are more obviously un-satisfied.
Thanks for the tip!
Clojure's = does a nested value check across types with similar properties. So yes.
what do you mean by βnestedβ check? like recursive?
(= [[1]] [[1]]) ;; => true (= [{:a :b}] [{:a :b}]) ;; => true recurisve would have been a better word.
nice!
> (= ()
(for [x ()] nil)
[]
(list)
(map identity []))
true
On a similar note, I usually use (frequencies)
to compare 2 maps (such as (= (frequencies map-one) (frequencies map-two))
). Is there a better way to check map equality, or is that the de-facto solution?
you should be able to do (= map-one map-two)
. are you seeing unexpected results?
Sorry, I mis-typed. I mean to compare lists independent of order. I've been comparing lots of lists of maps, which is why I remembered wrong.
> (= {:a 1}
(hash-map :a 1))
true
comparing frequencies seems reasonable for comparing seqs in an order independent way. depending on the situation, it might also be a hint that you're using the wrong data structure
In Sean Corfield's usermanager example, compojure handlers are specified with a leading #'
. The app has a model view controller architecture, and within the controller, calls to (assoc-in request ...)
are used "add" data into the request map and pass it into the views. I find the same thing in a similar example using reitit, for example ["/list" {:handler #'user-ctl/get-users}]
#'
is called var quote, and it gives the var that a name refers to instead of the value of the var the name refers toIn my experimentation with building an MVC app using reitit, I've found that (assoc-in request ...)
does not work unless I specify the handlers with a leading #
` . I also seem to be having issues passing form params into the controller for processing. In a functional sense, what is this doing in this case?
user=> (def x 1)
#'user/x
user=> x
1
user=> #'x
#'user/x
user=> (deref #'x)
1
user=> @#'x
1
user=>
which is why if you define a function f, then define a function g which uses f, then redefine f, g will use the new definition
g refers to f through the mutable var, and if you redefine f it just mutates the var
vars have a useful feature that they can be invoked like functions, and when you invoke like functions they just invoke whatever value they have with whatever arguments where passed
passing vars instead of functions allows you to update by defining the vars, and have the server pickup the new behavior without being restarted
What makes this behavior different when running the server? in pure clojure function g implicitly uses the var's new definition for f, by just using f's name, but with the server you need to pass the var directly
@kaxaw75836 It's not about "server" vs "pure clojure" -- it's about contexts where the (current) value of the function is captured and therefore new definitions of it are not seen.
Here's a REPL session that shows where this comes into play:
user=> (defn f [g] (fn [coll] (map g coll)))
#'user/f
user=> (defn q [n] (inc n))
#'user/q
user=> (def ff (f q))
#'user/ff
user=> (ff (range 5))
(1 2 3 4 5)
user=> (defn q [n] (dec n))
#'user/q
user=> (ff (range 5))
(1 2 3 4 5)
user=> (defn q [n] (inc n))
#'user/q
user=> (def ff (f #'q))
#'user/ff
user=> (ff (range 5))
(1 2 3 4 5)
user=> (defn q [n] (dec n))
#'user/q
user=> (ff (range 5))
(-1 0 1 2 3)
user=>
Note how the first redefinition of q
is not picked up by ff
-- we still get the inc
-based version -- but in the second section, where ff
was def
'd to use a Var reference #'q
, the redefinition of q
(to use dec
) is picked up by ff
in that last call.
When is it necessary too pass a var reference? It seems like you could either pass the var or use dynamic binding. Both of which I see more often and so I would argue are more clear to me.
The dynamic binding is likely to be less convenient in this case (handlers and middleware), both in the REPL and in use in the program. It can be a good fit for a call-tree-specific value for a "global" though.
The issue is communication. Passing the #' like that means the caller has no chance to trace back where that change happened in the code. Not in anyway i know of short of reading every expression read in. I would use the dynamic var to represent the default case then rebinding when the default wasn't sufficient:
(defn ^:dynamic *q* [h] (dec h))
(defn f
([coll] (map *q* coll))
([coll q]
(binding [*q* q]
(map *q* coll))))
(f (range 5))
;; => (-1 0 1 2 3)
(f (range 5) inc)
;; => (1 2 3 4 5)
This was a pattern discussed in elements of clojure which i had to reference. under "no one should have to know you used binding". That's not a call to authority, its more that if you happen to have the book he walks through his reasoning in some detail so it might provide more context here then i am.That's not the same issue we're discussing here tho'. Using #'
is specifically about development and REPL usage, so you can update the function definition, eval the top-level form, and have the changes picked up without restarting your server process.
#'
isn't about changes "happening in the code" -- it's about changes via the REPL.
If you're in a situation where a dynamic Var makes sense then, sure, EoC is good advice to "hide" the binding
form. That's great for default behavior that you might want to override further up the call chain.
Is there something you can do with the reader macro that you can't do with the dynamic binding? I'm not seeing it if so. It just seems like a matter of convenancy. passing the reader macro means that the change isn't caught by a lexical scope. I'm argueing that makes it harder to follow back to see why things changed. (defn g [coll] (f coll)) ;; top level rebind / restart the server: (binding [q inc] (g (range 5))) ;; => (1 2 3 4 5)
i guess in terms of searching it would be (ff (range 5)) and then i would look up (def ff (f #'q)) and (def ff (f q)) so the downside is that i might miss that it was redefined.
err. it would be that i have no idea which of those two were evaled last?
You seem to be completely missing the point of this discussion...
binding
is not a good solution to writing REPL-friendly code.
See https://clojure.org/guides/repl/enhancing_your_repl_workflow#writing-repl-friendly-programs
Ah. I see, we have to alter the in the global context because thats the only avenue to the "running" repl.
Right. It's why you'll see a combination of Var-quote references and also some regular global Vars that are manipulated via alter-var-root
-- neither of which make sense as a "general" programming technique but are useful in a REPL development context. We use Component heavily at work and our normal usage is something like
(defn -main [& args]
(let [app (component/start (build-system (parse args)))]
(process app)
(component/stop app)
(shutdown-agents))
but in the REPL we'd use stuff like this
(defonce ^:private sys (build-system {:some "stuff"}))
...
(alter-var-root #'sys component/start)
...
(process sys)
...
(alter-var-root #'sys component/stop)
(all in a Rich Comment Form)
Some of our apps that we tend to run Socket REPLs in have an extra line in -main
that does (alter-var-toot #'sys (constantly app))
once the component is started, before the process
call. That way we can connect into the running process and get access to the core application system via a global at the REPL.
This is essentially the pattern used in middleware and (some) routing definitions in web apps in Clojure, which is why it matters.
@seancorfield Thanks for the explanation. It's a subtle but essential point that isn't highlighted in router docs or simple examples. Very thankfully, changing my router handlers to use var references solved all the mysterious issues I was having. Suddenly, data is persisting properly to a datomic dev-local instance from a form and I have a list of that data displaying in my app! π