This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-03-27
Channels
- # announcements (3)
- # aws (7)
- # babashka (11)
- # beginners (96)
- # clojure (15)
- # clojure-europe (9)
- # clojure-germany (2)
- # clojure-italy (1)
- # clojure-nl (3)
- # clojure-poland (3)
- # clojure-serbia (1)
- # clojurescript (13)
- # depstar (28)
- # fulcro (34)
- # graalvm (5)
- # honeysql (5)
- # malli (11)
- # off-topic (27)
- # pathom (9)
- # polylith (74)
- # portal (10)
- # re-frame (13)
- # releases (1)
- # ring (8)
- # shadow-cljs (3)
- # spacemacs (10)
- # tools-deps (8)
Another option is to use some
:
user=> (some #(when-not (% nil) %) [int? zero?])
#object[clojure.core$int_QMARK_ 0x57dc9128 "clojure.core$int_QMARK_@57dc9128"]
user=>
You need (when-not (% nil) %)
to get the actual predicate back
Hi there. Is there a way to do something like (? value preds)
where it will run value
through preds
and return false
if any of the preds fails and true
otherwise? Thanks in advance.
@rextruong Use every?
like this:
user=> (every? #(% 42) [int? pos? even?])
true
user=> (every? #(% 43) [int? pos? even?])
false
@seancorfield Iāve thought of that but just wondering if there was a āshorterā way to do it
user=> ((every-pred int? pos? even?) 42)
true
user=> ((every-pred int? pos? even?) 43)
false
If you have a collection of predicates, you'd need (apply every-pred preds)
Any carmine (redis) guys?
@kishorekaranam99 I really don't think many people use Carmine. You've asked three times now in different channels and no one has responded. You asked on ClojureVerse and I told you we'd moved off it (and no one else answered).
@kishorekaranam99 Iāve used it a very a long time ago but Iāve since made the conscious decision to avoid Redis as much as possible;
IMO it strikes a confused middle ground between a cache and a database. Not something I want to use.
If you just want a cache without any on-disk persistence, you can probably achieve very similar to Redis results by simply using a Clojure atom (or the STM if really needed) + the built-in Clojure data structures: maps, sets, vectors, sorted-maps; Iāve built a simple/naive in-memory āsearchā service that way; itās very easy to achieve correctness + super fast. Of course, no on-disk persistence.
We still use Redis very heavily but we gave up on Carmine, switched to Redisson (and Java interop) and then switched to plain old Jedis via Java interop (because Redisson was a HUGE dependency and was very slow to become compatible with Java 9+ as I recall? Or maybe it was one of Redisson's (many) transitive dependencies?).
We use Redis for pub/sub and also the TTL key/value stuff, but Jedis is sufficient. We did write our own connection pooling logic for it because the built in one was problematic (in some way I don't remember -- my teammate could talk about that perhaps).
@seancorfield do you guys run on AWS or your own data center?
We run on a private cloud in a managed data center. So, not quite any of the above
Historical reasons: we used EdgeWeb Hosting for years before I joined, we switched to Clojure and just stayed with them, and now they're part of DataBank so they have plenty of data centers and a lot of VM experience.
(and we're very small so we have no in-house ops talent)
Understood; you mentioned pub/sub and I thought of AWS SQS; but if youāre not on AWS, it probably doesnāt make sense.
Redis pub/sub is a thing š
Hello Clojurians. I was trying to get back into Clojure and thought of just trying out reducers to get the average of a sequence of numbers. I saw online that the most elegant way to do so is:
(defn average [coll]
(/ (reduce + coll) (count coll)))
Unfortunately this loops over the collection twice and wondered if there's anything better than this that is still elegant. Personally, my attempt was this:
(defn mean
[xs]
(->> xs
(reduce (fn [acc n]
{:total (+ n (acc :total))
:count (inc (acc :count))})
{:total 0 :count 0})
(vals)
(apply /)))
(defn mean [xs]
(let [[total count] (reduce (fn [[t n] x] [(+ t x) (inc n)]) [0 0] xs)]
(/ total count)))
How about that @gitere81?Thanks @seancorfield! This does omit the extra call to vals
from before. I guess the function given to reduce can be extracted to its own defn
for readability.
@gitere81 one more alternative using a library and transducers: https://github.com/cgrand/xforms
(transduce
(map identity)
net.cgrand.xforms.rfs/avg
[2 4 6])
=> 4BTW, if your xs
is a vector rather than a sequence then count
is O(1) because vectors know their size so it doesnāt āloop over the collectionā
So your initial (defn average [coll] (/ (reduce + coll) (count coll)))
is pretty efficient if coll
is a vector.
Alright. I assumed all sequences have their count lazily evaluated.
Sequences generally, yes. Collections, not always.
Have a read of this https://clojure.org/reference/data_structures which talks about performance guarantees of different collections. Also https://clojure.org/reference/sequences which talks about sequences.
@gitere81
(let [s (repeat 1000000 0)
v (mapv identity s)]
(time (count s))
(time (count v)))
This is probably the first time I've seen identity
being used lol. Again, I have barely scratched the surface of Clojure
Yup, identity
is one of those weird things that you think āWhat? Why would anyone want a function that does nothing?ā and yet it turns out to be quite useful in functional programming.
(we have about 150 instances of identity
in our codebase at work)
I really prefer sticking to vectors/collections as much as possible unless thereās a specific need to use sequences; Easier to reason about IMO
š I will try to find more situations to use mapv
when I can
Also, do Slack code blocks allow for language specific formatting?
(MacOS) Cmd + Shift + C ā¦ still feels clunky sometimes but it works most of the time
You can add āCode snippetsā which I think have some language-specific formatting but most folks just use plain triple-backticksā¦
Snippet using Clojure formatting
(I typed /snip
and it offered a code snippet option)
(you have to tell it to use Clojure ā it doesnāt auto-detect it)
In this page https://clojure.org/news/2021/03/18/apis-serving-people-and-programs, it says, > For example, a function that takes a sequence and optional keyword arguments and returns a vector containing the values is defined as:
(defn destr [& {:keys [a b] :as opts}]
[a b opts])
(destr :a 1)
->[1 nil {:a 1}]
(destr {:a 1 :b 2})
->[1 2 {:a 1 :b 2}]
But where is the sequence here? Is this a typo?Itās a typo: it should say takes a sequence of optional keyword arguments
Can we use doto
with an unknown number of arguments? E.g. for every key value pair in a map, call a Java setter with the key and the value as two arguments.
I think I might use doseq for that. https://clojuredocs.org/clojure.core/doseq
@hindol.adhya Thereās also org.clojure/java.data
for that sort of thing: https://github.com/clojure/java.data
Looks like java.data has some nice facilities. to-java function can take a map and use it to call setters. Looks a little like magic though. Good to know this library exists. Thanks.
There isn't actually too much magic to it. clojure.lang.IPersistentMap
is an interface, and you can implement that interface on your own types.
Here's an example: https://gist.github.com/david-mcneil/1684980#file-custom-clojure-map-clj-L78-L116
(maps also implement java.lang.Iterable, clojure.lang.Associative, clojure.lang.IPersistentCollection, clojure.lang.Seqable and clojure.lang.ILookup. Caveat: this is still new to me, but I think this is correct)
@hindol.adhya Itās based on Javaās built-in Reflection APIs so itās as āmagicā as that š
Iāve learned the basics of Clojure and liking it a lot. But now I want to understand the tools surrounding it. Iām thinking to just start a simple empty folder and learn deps.edn with the clj tool, doing everything manually step by step to understand. Is that a good approach? Any suggestions on good books/guides/articles covering the Clojure tools in that manner?
Well in its simplest deps.edn is just a hash map containing two important keys :paths and :deps which have the values of respectively a vector of paths to your source code and other resources relative to your deps.edn file and a hashmap containing your dependencies, I guess the latter is a bit tricky
{:paths [āsrcā] :deps {cheshire/cheshire {:mvn/version ā5.10.0"} org.clojure/data.json {:mvn/version ā1.0.0ā} org.clojure/data.csv {:mvn/version ā1.0.0"}}}
I think you can go pretty far with just that
in clojars you can even copy and paste the syntax for the dependencies: i.e. https://clojars.org/io.randomseed/bankster
then you need to put require forms in your ns declaration on the top of your file
oh and running is just clj while in the same directory to pull the dependencies
and clj -m <namespace containing your main function> to run your app
the above is the tl;dr you can always also read https://clojure.org/guides/deps_and_cli for more details
@dimitar.ouzounoff Thank you! I know most of this, more or less, but I think what Iām missing is the āwhyā - why did clj and deps come about, what are they replacing, what context does the clj tools exist in in general? Etc. I think I just want to make up for my complete lack of experience of the clj and jvm world...
https://clojureverse.org/t/how-to-effectively-use-deps-cli/4787/4?u=duzunov - I think this thread can be useful for context
before tools.deps there was leiningen which is a more traditional build tool
build tools traditionally are separate tools from the language - like for example when writing C you will use a Makefile - a totally different, declarative language to build your program
@hindol.adhya Thereās also org.clojure/java.data
for that sort of thing: https://github.com/clojure/java.data
would identity
be similar to this
in other langs?
maybe i just need to see more examples of identity
this
would be a big ball of spaghetti with methods and variables... identity
just "returns its argument" ... okay i think that makes sense... thank you @ghadi
@sova Something Iāve used it for in the past: (into {} (map (juxt :id identity)) data)
to turn a sequence of hash maps containing :id
into a hash map indexed by the ID (whose values are the original hash maps).
dev=> (into {} (map (juxt :id identity)) [{:id 1 :foo "bar"} {:id 2 :a 1 :foo "quux"}])
{1 {:id 1, :foo "bar"}, 2 {:id 2, :a 1, :foo "quux"}}
I've used it to "recycle" functions, in this case I wrote a function to get a particular element inside the payload from the body of a http response:
(defn response-element
"Gets the desired element from the payload coming from a http response"
[response element]
(-> response
:body
(json/read-str :key-fn keyword)
:payload
element))
So I used it like this: (response-element response :some-key)
. Later I found out that sometimes I needed the whole payload and instead of making a new function I could use the same one using identity
: (response-element response identity)
. It's a nice thing that keywords are functions too.I'm pretty sure I've come across a very easy way to convert a vector like this: [:a 1 :b 2]
to a map like this {:a 1 :b 2}
... how do I actually do it though? can't figure it out anymore
(apply hash-map [:a 1 :b 2])
If you have a sequence of key/value pairs like [[:a 1] [:b 2]]
you can use (into {} [[:a 1] [:b 2]])
what should you do if you have a nice chain with 5 forms where ->
works perfectly, but then have one in the middle where you'd need ->>
? some stupid thing like (#(func arg1 arg2 %))
?
I usually mutter under my breath and then use as->
If the form should go in the last position, ->>
in a ->
pipeline is the ācorrectā thing. It the form should go elsewhere, then as->
might be right. But: https://stuartsierra.com/2018/07/06/threading-with-style (and read all his other doās and donāts).