This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (16)
- # babashka (10)
- # beginners (80)
- # calva (18)
- # cider (10)
- # clojure (96)
- # clojure-austin (1)
- # clojure-europe (52)
- # clojure-france (6)
- # clojure-germany (2)
- # clojure-italy (4)
- # clojure-nl (4)
- # clojure-seattle (3)
- # clojure-spec (4)
- # clojure-uk (25)
- # clojurescript (97)
- # community-development (2)
- # cursive (7)
- # datomic (13)
- # figwheel-main (5)
- # fulcro (13)
- # inf-clojure (1)
- # jobs (3)
- # off-topic (33)
- # pathom (10)
- # polylith (8)
- # re-frame (7)
- # reitit (8)
- # releases (1)
- # reveal (2)
- # ring (4)
- # ring-swagger (1)
- # sci (6)
- # shadow-cljs (102)
- # slack-help (1)
- # spacemacs (28)
- # tools-deps (9)
- # vim (1)
- # xtdb (3)
Currently I have a function like follows:
However, this means that for every query, I have to make two trips to the database. What would be the best way to rewrite this in clojure so it only has to make one query per condition, and does not have to make the subsequent queries until knowing that the previous queries are empty?
(cond (-> db/query-a seq) (-> db/query-a first process) (-> db/query-b seq) (-> gb/query-b first process) ... (-> db/query-n seq) (-> db/query-n first process)
(if-some [qa (not-empty db/query-a)] (-> qa first process) (if-some [qb (not-empty db/query-b)] (-> qb first process) ...))
not-empty looks neat, I poked around for a
cond-some and stumbled upon https://github.com/Engelberg/better-cond which I will give a go
https://clojuredocs.org/clojure.core/condp has an overload that allows to pass result of condition to the function
(condp #(-> (%1 %2) seq) db db/query-a :>> #(-> % first process) db/query-b :>> #(-> % first process))
@U076FM90B That's perfect! It will take me a while to parse through but I will try to use it - good learning op 😄
condp is a little weird (eg. how it scrambles the args provided), but can really DRY up code
also, this pattern could be replaced by "or", since the condp function is pure glue with hardly any logic:
(first already implicitly calls seq, but it's safe to call it twice)
(process (first (or (seq db/query-a) (seq db/query-b) ... (seq db/query-n)))))
but you would want to stop if none were true, but that's a simple flip
(some-> (some seq [query-a query-b ... query-n]) (first) (process))
(I also realized a coll plus
some seq is simpler than calling seq on each item)
I need your help. I do remember a Clojure environment mentioned in a blog post. As far as I recall this was a standalone environment (single JAR?) and praised by the author for its simplicity and beginner friendliness, because it meant that you could instantly start coding from anywhere without a full-blown IDE. Does this ring a bell with anyone? Is it possible that this tool has been shipped with the official Clojure distribution in earlier times? It might also have been part of another tool, or maybe ClojureScript. I tried googling a lot, but to no avail ("clojure gui" is a pretty overloaded search term -.- )
When it was some time back, maybe it was LightTable? http://lighttable.com
@U0N9SJHCH thanks for brining it up 👍
yeah, light table got a bunch of buzz and had some high quality talks hyping it, but the project seems to have fizzled
oh, it's still under development
https://github.com/oakes/Nightlight (successor to https://github.com/oakes/Nightcode which is probably the one you were thinking of)
Both repos are archived on Github
hash on a zipper returns a different value at each call. Does anyone know why?
(a consequence of this is that
= isn't consistent either)
If you define your functions inline, that's probably why:
cljs.user=> (= (fn ) (fn )) false cljs.user=> (hash (fn )) 1 cljs.user=> (hash (fn )) 2
Yes, I figured it out. I think that's the reason.
hash on Clojure functions are based on identity of that function object in memory.
Yeah, that makes sense.
I have not looked at the implementations of zippers in Clojure carefully -- are you saying that they involve storing reference to Clojure functions inside of the data structure?
Hmmm. OK. I somehow thought they had ways of representing them without doing that -- but again, I have never looked closely.
Oh no, sorry, misread your question
I am myself storing functions in the zipper, that doesn't have anything to do with the implementation itself
OK. Doing that will cause the same issues of those functions having
hash based on identity, no matter which immutable collections you make them a part of in Clojure.
a function reference defined with
def should work though?
Depends upon what you mean by "work".
I mean that
hash should be consistent
If I do
(defn foo [x] (inc x)) followed by
(def bar foo), then
(identical? foo bar) should be true.
If I do
(def foo (fn [x] (inc x))) followed by
(def bar (fn [x] (inc x))) then
(identical? foo bar) should be false.
Each invocation of
fn creates a new function object.
There might be exceptions to that statement, but I'm hard pressed to think of one, and relying on such behavior seems very fragile to me.
yeah, a function identifier and a identifier->function map seems more reliable
Using an immutable value like a string, keyword, or symbol as an identifier -- definitely.
If it matters to you to be able to distinguish such immutable values by some kind of 'type' from other immutable values, you could even create a new type with
defrecord that has one field that is the string/keyword/symbol, but that might be overkill for your needs.
Hi, I think I’ve hit a bug when using compojure-api with ring-swagger. When using a custom JSON encoder the swagger.json file also changes, rendering the spec invalid. More details here https://github.com/metosin/compojure-api/issues/449 - any ideas?
and many assoc after using java interop , works
ITransientMap tm = (ITransientMap) transientC.invoke(PersistentHashMap.EMPTY);
its not a problem i just used the HashMap,but why ArrayMap didnt work? only some members added,2 keys that had big values didnt added
@takis_ transients only accidentally update in place, the correct way to use them is to use the return value of the updating function in place of the original object
as you've seen, adding to it does work as mutation for a few thing, until it stops working
oh its my fault, i knew that transients works as persistent,i will retry it,i forgot the assign again
ArrayMap tends to work best for small sizes (and auto-promotes to HashMap when it gets larger)
I'm playing a bit with
compile. If I
(compile 'rebel-readline.main), a
rebel_readline dir gets created inside
clojure (and likewise for other transitive deps):
Is that expected behavior? It seems odd to me as a more normal structure would be to have
$ ls classes/rebel_readline clojure/ jline_api$char_at.class ...
rebel_readlineas sibling dirs, inside
@vemv it's probably expected since rebel-readline has namespaces with clojure in it: https://github.com/bhauman/rebel-readline/tree/master/rebel-readline/src/rebel_readline/clojure
clojure main is probably not compiled since there is already a compiled version on the classpath while you're compiling
If I’m dealing with a collection of Java objects, say
[i1 i2 i3 i4] and I need to do something like
(.setResult i1 i2) then
(.setResult i2 i3), etc., what’s the best way to do that? It looks like a reduction to me, but it’s only being done for side effects, so it doesn’t need to return anything. I think I’m just confusing myself at this point, because it seems like there should be a simple way to do this. Any suggestions?
you can use
(run! (fn [[a b]] (.setResult a b)) (map vector coll (rest coll)))
Yes! This is the half-remembered function I was searching for. Thanks!
with doseq you don't need the fn
(doseq [[a b] (partition 2 1 coll)] (.setResult a b))
= be perform in O(1) time if the output of
hash function for its arguments is the same?
i believe by the pigeonhole principle it cannot. If we admit there are an infinite amount of hashable items and a finite number of hashes, hash would destroy equality if used in this manner.
That would make sense, but it's also very unlikely
There are only 2^32 different 32-bit hash values.
There are far more than 2^32 possible Clojure values that can be hashed and used as a key in a hash map, or an element in a hash set.
Many pairs of such values must have the same hash value.
So I guess the answer is no.
If hash is implemented correctly, it is safe to assume that (hash x) being different than (hash y) implies that x is not equal to y
(= (reify Object (hashCode [_] 42)) (reify Object (hashCode [_] 42))) is a direct answer
If hash is implemented incorrectly, then even that assumption is not safe.
Regarding "very unlikely" if hash is "evenly distributed" or you use "random values" then with 2^32 possible values, there is fun thing called "Birthday Paradox" (not really a paradox, really more of a 'surprising non-obvious fact') that says whenever you have about the square root of the number of "hash buckets" (2^32 square root is 2^16 = 65,536), then you are 50% likely to have a collision.
That is for "uniform randomly distributed values" -- it is of course possible to know more about your data set and how they are distributed, that could change that likelihood of collision.
Hmm I see, yes I heard about that before
So if you have a hash map or hash set with 65,536 items, about half the time at least two of those will collide in their hash values, and Clojure's implementation will put such items in a linear linked list.
(a separate linear linked list per hash value, not one common linked list for the hash-map/hash-set as a whole)
Oh ok, that's interesting
That Birthday Paradox is one of the reasons that UUIDs have as many bits as they do. 32 bits is far too small for the use case that UUIDs are for.
So that means the colliding values in a hashset are tested not against their hash, but in a O(n) comparison
The colliding values in a hash set all have equal hash values, so they cannot be told apart by their hash values alone. You have to do a linear search and do clojure.core/= on the searched value and the ones in the collection that collide.
Even if there are no collisions, you have to do clojure.core/= on a searched-for value and the one in the collection with the same hash, because even though they have the same hash, they might return false for clojure.core/=