chunking doesn't play nicely with laziness http://www.tianxiangxiong.com/2016/11/05/chunking-and-laziness-in-clojure.html
thank you
to verify that chunkiness is the problem:
(defn dechunk [s]
(lazy-seq
(when-let [[x] (seq s)]
(cons x (dechunk (rest s))))))
(first (remove #(% nil) (dechunk [int? zero?])))
I prefer creamy sequences over chunky, myself
i like the crunch of the chunk
you can also use transducers to avoid laziness if you prefer
personally I think laziness-by-default was a design mistake in Clojure
i have a user-supplied value that i need to apply a series of value checks to, defined in an external schema
schema as a vector that will provide a bottoms-up series of truthy tests to the value
was curious how to handle a nil
transducer version:
(into [] (comp (remove #(% nil)) (take 1)) [int? zero?])
you could also just use reduce
that's curious.
chunking
reduce will still need to be in transducer form, correct?
(reduce #(%2 1) [int? pos?]) => true
(reduce #(%2 1) [int? even?]) => false
(reduce #(%2 nil) [int? even?]) => NPE
or more appropriate non-transducer version:
(reduce #(conj %1 (%2 1)) [] [even? int?]) => [false true]
seems like you want short-circuiting, in which case you'd use and
in the reduce to produce a single bool
yea. i think thats why i picked remove as the primary form. the first eval (int? even?) that returns false, i can take 1 and short circuit
but first calls seq, which is where your link on chunking comes into play
you can use reduced
to short-circuit a reduce
call: https://clojuredocs.org/clojure.core/reduced
thanks, darin. will check that out
in the case of transducers, do all of the comp params need to be transducable, too?
e.g. in the case of your example, you use (take 1) in it's transducer form
outside of a transducer context, i could use first. but it doesn't seem to want to apply here..
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
I just found every-pred
😅
@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)
they all need to be transducers, yes. first
doesn't have a transducer arity, I guess because take
can do that already
Will do. Thanks a lot 🙂
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.
oh
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?
Or other Azure/Google/etc
We run on a private cloud in a managed data center. So, not quite any of the above
Got it
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 🙂
Yeah I know 🙂
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.
TL;DR: collection = concrete, sequence = abstract.
@gitere81
(let [s (repeat 1000000 0)
v (mapv identity s)]
(time (count s))
(time (count v)))
“Elapsed time: 444.196333 msecs” “Elapsed time: 0.013042 msecs” 1000000
This is probably the first time I've seen identity
being used lol. Again, I have barely scratched the surface of Clojure
🙂 It’s literally
(defn identity
"Returns its argument."
[x] x)
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
mapv
is my friend 🙂
😂 I will try to find more situations to use mapv
when I can
Also, do Slack code blocks allow for language specific formatting?
Or transducers:
(into [] (map identity) (repeat 1000 0))
(MacOS) Cmd + Shift + C … still feels clunky sometimes but it works most of the time
Not sure about lang. specific
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)
Ha, that’s good to know 🙂 Even if I’m not a fan of the color scheme
(you have to tell it to use Clojure — it doesn’t auto-detect it)
Yup, just tested that hah 🙂
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
Since it’s come up a couple of times, I just submitted a PR to fix it.
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
Yeah, doseq
seems to be the best way.
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
would identity
be similar to this
in other langs?
not really - identity is a function, this is a reference/object
hmmmm
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])
yep, thank you very much! 🙂
If you have a sequence of key/value pairs like [[:a 1] [:b 2]]
you can use (into {} [[:a 1] [:b 2]])
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 🙂
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 %))
?
(-> my-input
form1
(->> map identity)
form2)