In case your conditions to navigate are getting more and more complex, have a look to specter : https://github.com/redplanetlabs/specter
Currently I have a function like follows:
(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)
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?thanks @p-himik! 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
(condp #(-> (%1 %2) seq) db
db/query-a :>> #(-> % first process)
db/query-b :>> #(-> % first process))
https://clojuredocs.org/clojure.core/condp has an overload that allows to pass result of condition to the function@nbardiuk That's perfect! It will take me a while to parse through but I will try to use it - good learning op π
Thanks!
yeah, 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:
(process
(first
(or (seq db/query-a)
(seq db/query-b)
...
(seq db/query-n)))))
(first already implicitly calls seq, but it's safe to call it twice)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)
(if-some [qa (not-empty db/query-a)]
(-> qa first process)
(if-some [qb (not-empty db/query-b)]
(-> qb first process)
...))
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 -.- )
Klipse? https://github.com/viebel/klipse
https://github.com/oakes/Nightlight (successor to https://github.com/oakes/Nightcode which is probably the one you were thinking of)
Looks interesting, thank you. But somehow I remember having a native app.
Thanks, that is indeed a good candidate... if my memory just wasn't so blurry π
When it was some time back, maybe it was LightTable? http://lighttable.com
@javahippie thanks for brining it up π
Both repos are archived on Github
Hello, 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.
=
and 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?
Yes.
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 =
and hash
based on identity, no matter which immutable collections you make them a part of in Clojure.
Yes
a function reference defined with def
should work though?
Depends upon what you mean by "work".
I mean that =
and hash
should be consistent
If I do (defn foo [x] (inc x))
followed by (def bar foo)
, then (identical? foo bar)
should be true.
I see
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 defn
or fn
creates a new function object.
yes
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.
Yes
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.
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
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?
hello ,
ITransientMap tm = (ITransientMap) transientC.invoke(PersistentHashMap.EMPTY);
and many assoc after using java interop , worksITransientMap tm = (ITransientMap) transientC.invoke(PersistentArrayMap.EMPTY);
and many assoc after using java interop , doesnt work
i am using them in wrong way? i know that ArrayMap becomes auto HashMap
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
yes now its fine it was bug i forgot it , thank you noisesmith π
for perfomance reasons,what to use?
i should start with ArrayMap or HashMap?
some maps can be very small in my app even 2 members
anyway i will test it i guess ArrayMap better , thanks :)
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 classes
, containing clojure
(and likewise for other transitive deps):
$ ls classes/rebel_readline
clojure/ jline_api$char_at.class
...
Is that expected behavior? It seems odd to me as a more normal structure would be to have clojure
and rebel_readline
as sibling dirs, inside classes
@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
(which is maybe not allowed by our bd, but that's a different issue)
ahhhh that confused me lots :) I thought I was looking at the real clojure.main
clojure main is probably not compiled since there is already a compiled version on the classpath while you're compiling
correct
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!
:
(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))
Hey, will =
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.
I see
That would make sense, but it's also very unlikely
(count (into #{} [(reify Object (hashCode [_] 42)) (reify Object (hashCode [_] 42))]))
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.
Indeed
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
and (= (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/=
Yes