beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Michael Gardner 2021-03-27T00:02:38.125500Z

chunking doesn't play nicely with laziness http://www.tianxiangxiong.com/2016/11/05/chunking-and-laziness-in-clojure.html

Franco Gasperino 2021-03-27T00:03:36.125700Z

thank you

Michael Gardner 2021-03-27T00:04:00.125900Z

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?])))

Michael Gardner 2021-03-27T00:04:40.126100Z

I prefer creamy sequences over chunky, myself

Franco Gasperino 2021-03-27T00:05:00.126300Z

i like the crunch of the chunk

Michael Gardner 2021-03-27T00:05:22.126500Z

you can also use transducers to avoid laziness if you prefer

Michael Gardner 2021-03-27T00:05:41.126700Z

personally I think laziness-by-default was a design mistake in Clojure

Franco Gasperino 2021-03-27T00:05:46.126900Z

i have a user-supplied value that i need to apply a series of value checks to, defined in an external schema

Franco Gasperino 2021-03-27T00:06:14.127100Z

schema as a vector that will provide a bottoms-up series of truthy tests to the value

Franco Gasperino 2021-03-27T00:06:31.127300Z

was curious how to handle a nil

Michael Gardner 2021-03-27T00:06:32.127500Z

transducer version:

(into [] (comp (remove #(% nil)) (take 1)) [int? zero?])

Michael Gardner 2021-03-27T00:07:52.127700Z

you could also just use reduce

1👆
sova-soars-the-sora 2021-03-27T00:14:10.128Z

that's curious.

Franco Gasperino 2021-03-27T00:14:23.128200Z

chunking

Franco Gasperino 2021-03-27T00:20:28.128400Z

reduce will still need to be in transducer form, correct?

Franco Gasperino 2021-03-27T00:23:00.128600Z

(reduce #(%2 1) [int? pos?]) => true
(reduce #(%2 1) [int? even?]) => false
(reduce #(%2 nil) [int? even?]) => NPE

Franco Gasperino 2021-03-27T00:25:10.128800Z

or more appropriate non-transducer version:

(reduce #(conj %1 (%2 1)) [] [even? int?]) => [false true]

Michael Gardner 2021-03-27T00:28:00.129Z

seems like you want short-circuiting, in which case you'd use and in the reduce to produce a single bool

Franco Gasperino 2021-03-27T00:28:54.129200Z

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

Franco Gasperino 2021-03-27T00:29:16.129400Z

but first calls seq, which is where your link on chunking comes into play

Darin Douglass 2021-03-27T00:29:51.129600Z

you can use reduced to short-circuit a reduce call: https://clojuredocs.org/clojure.core/reduced

Franco Gasperino 2021-03-27T00:33:32.129800Z

thanks, darin. will check that out

Franco Gasperino 2021-03-27T00:34:03.130Z

in the case of transducers, do all of the comp params need to be transducable, too?

Franco Gasperino 2021-03-27T00:34:22.130200Z

e.g. in the case of your example, you use (take 1) in it's transducer form

Franco Gasperino 2021-03-27T00:34:41.130400Z

outside of a transducer context, i could use first. but it doesn't seem to want to apply here..

seancorfield 2021-03-27T00:49:26.131300Z

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=>

seancorfield 2021-03-27T00:49:47.132Z

You need (when-not (% nil) %) to get the actual predicate back

aratare 2021-03-27T00:50:41.133Z

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.

seancorfield 2021-03-27T00:52:15.133600Z

@rextruong Use every? like this:

user=> (every? #(% 42) [int? pos? even?])
true
user=> (every? #(% 43) [int? pos? even?])
false

aratare 2021-03-27T00:52:21.133700Z

I just found every-pred 😅

aratare 2021-03-27T00:52:55.134300Z

@seancorfield I’ve thought of that but just wondering if there was a “shorter” way to do it

seancorfield 2021-03-27T00:53:25.135Z

user=> ((every-pred int? pos? even?) 42)
true
user=> ((every-pred int? pos? even?) 43)
false

1👍
seancorfield 2021-03-27T00:53:46.135600Z

If you have a collection of predicates, you'd need (apply every-pred preds)

Michael Gardner 2021-03-27T00:54:01.135800Z

they all need to be transducers, yes. first doesn't have a transducer arity, I guess because take can do that already

aratare 2021-03-27T00:54:18.136100Z

Will do. Thanks a lot 🙂

finchharold 2021-03-27T05:14:53.136500Z

Any carmine (redis) guys?

seancorfield 2021-03-27T05:43:30.137600Z

@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).

1👍
raspasov 2021-03-27T05:58:57.138700Z

@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;

raspasov 2021-03-27T05:59:36.139200Z

IMO it strikes a confused middle ground between a cache and a database. Not something I want to use.

finchharold 2021-03-27T05:59:45.139400Z

oh

raspasov 2021-03-27T06:03:46.142700Z

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.

seancorfield 2021-03-27T06:05:02.144300Z

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?).

seancorfield 2021-03-27T06:08:34.145700Z

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).

raspasov 2021-03-27T06:08:58.146Z

@seancorfield do you guys run on AWS or your own data center?

raspasov 2021-03-27T06:09:20.146700Z

Or other Azure/Google/etc

seancorfield 2021-03-27T06:09:34.147Z

We run on a private cloud in a managed data center. So, not quite any of the above

raspasov 2021-03-27T06:09:41.147200Z

Got it

seancorfield 2021-03-27T06:10:39.148400Z

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.

seancorfield 2021-03-27T06:10:57.149100Z

(and we're very small so we have no in-house ops talent)

raspasov 2021-03-27T06:12:08.150Z

Understood; you mentioned pub/sub and I thought of AWS SQS; but if you’re not on AWS, it probably doesn’t make sense.

seancorfield 2021-03-27T06:12:24.150200Z

Redis pub/sub is a thing 🙂

raspasov 2021-03-27T06:12:56.150700Z

Yeah I know 🙂

Kenneth Gitere 2021-03-27T06:23:14.152500Z

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)))

Kenneth Gitere 2021-03-27T06:24:39.153800Z

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 /)))

seancorfield 2021-03-27T06:26:56.155600Z

(defn mean [xs]
  (let [[total count] (reduce (fn [[t n] x] [(+ t x) (inc n)]) [0 0] xs)]
    (/ total count)))
How about that @gitere81?

Kenneth Gitere 2021-03-27T06:31:12.157500Z

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.

raspasov 2021-03-27T06:32:31.158500Z

@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])
=> 4

1👍
seancorfield 2021-03-27T06:32:32.158600Z

BTW, 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”

seancorfield 2021-03-27T06:33:23.159400Z

So your initial (defn average [coll] (/ (reduce + coll) (count coll))) is pretty efficient if coll is a vector.

1👆
Kenneth Gitere 2021-03-27T06:34:46.160600Z

Alright. I assumed all sequences have their count lazily evaluated.

seancorfield 2021-03-27T06:35:42.161400Z

Sequences generally, yes. Collections, not always.

seancorfield 2021-03-27T06:37:31.162100Z

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.

seancorfield 2021-03-27T06:38:51.162600Z

TL;DR: collection = concrete, sequence = abstract.

1👍
raspasov 2021-03-27T06:39:57.163300Z

@gitere81 (let [s (repeat 1000000 0) v (mapv identity s)] (time (count s)) (time (count v)))

raspasov 2021-03-27T06:40:13.163500Z

“Elapsed time: 444.196333 msecs” “Elapsed time: 0.013042 msecs” 1000000

Kenneth Gitere 2021-03-27T06:43:26.165500Z

This is probably the first time I've seen identity being used lol. Again, I have barely scratched the surface of Clojure

raspasov 2021-03-27T06:44:11.166200Z

🙂 It’s literally

(defn identity
  "Returns its argument."
  [x] x)

seancorfield 2021-03-27T06:44:52.167300Z

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.

seancorfield 2021-03-27T06:45:55.168700Z

(we have about 150 instances of identity in our codebase at work)

raspasov 2021-03-27T06:45:55.168800Z

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

raspasov 2021-03-27T06:46:20.169400Z

mapv is my friend 🙂

Kenneth Gitere 2021-03-27T06:46:55.170600Z

😂 I will try to find more situations to use mapv when I can

Kenneth Gitere 2021-03-27T06:47:25.171400Z

Also, do Slack code blocks allow for language specific formatting?

raspasov 2021-03-27T06:47:31.171600Z

Or transducers:

(into [] (map identity) (repeat 1000 0))

raspasov 2021-03-27T06:48:19.172500Z

(MacOS) Cmd + Shift + C … still feels clunky sometimes but it works most of the time

raspasov 2021-03-27T06:48:39.173100Z

Not sure about lang. specific

seancorfield 2021-03-27T06:48:39.173200Z

You can add “Code snippets” which I think have some language-specific formatting but most folks just use plain triple-backticks…

seancorfield 2021-03-27T06:49:46.173600Z

Snippet using Clojure formatting

seancorfield 2021-03-27T06:51:17.175100Z

(I typed /snip and it offered a code snippet option)

raspasov 2021-03-27T06:52:18.175900Z

Ha, that’s good to know 🙂 Even if I’m not a fan of the color scheme

seancorfield 2021-03-27T06:53:12.176500Z

(you have to tell it to use Clojure — it doesn’t auto-detect it)

raspasov 2021-03-27T06:53:29.176900Z

Yup, just tested that hah 🙂

hindol 2021-03-27T07:35:58.178400Z

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?

seancorfield 2021-03-27T07:37:13.178800Z

It’s a typo: it should say takes a sequence of optional keyword arguments

seancorfield 2021-03-27T07:39:58.179200Z

Since it’s come up a couple of times, I just submitted a PR to fix it.

4👍
hindol 2021-03-27T08:11:46.180700Z

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.

teodorlu 2021-03-27T08:44:34.180900Z

I think I might use doseq for that. https://clojuredocs.org/clojure.core/doseq

1👍
hindol 2021-03-27T09:47:00.181200Z

Yeah, doseq seems to be the best way.

2021-03-27T12:04:11.184Z

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?

Dimitar Uzunov 2021-03-27T12:42:55.186800Z

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

Dimitar Uzunov 2021-03-27T12:43:09.187Z

{: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"}}}

Dimitar Uzunov 2021-03-27T12:43:23.187300Z

I think you can go pretty far with just that

Dimitar Uzunov 2021-03-27T12:44:23.187900Z

in clojars you can even copy and paste the syntax for the dependencies: i.e. https://clojars.org/io.randomseed/bankster

Dimitar Uzunov 2021-03-27T12:47:25.189200Z

then you need to put require forms in your ns declaration on the top of your file

Dimitar Uzunov 2021-03-27T12:52:06.189700Z

oh and running is just clj while in the same directory to pull the dependencies

Dimitar Uzunov 2021-03-27T12:52:27.190300Z

and clj -m <namespace containing your main function> to run your app

Dimitar Uzunov 2021-03-27T12:54:33.191400Z

the above is the tl;dr you can always also read https://clojure.org/guides/deps_and_cli for more details

2021-03-27T13:05:33.194200Z

@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...

Dimitar Uzunov 2021-03-27T13:16:37.194800Z

https://clojureverse.org/t/how-to-effectively-use-deps-cli/4787/4?u=duzunov - I think this thread can be useful for context

Dimitar Uzunov 2021-03-27T13:18:52.195100Z

before tools.deps there was leiningen which is a more traditional build tool

Dimitar Uzunov 2021-03-27T13:21:30.195300Z

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

grazfather 2021-03-27T14:47:22.195500Z

Finally looking at this, this is a great example of why mutability is a nightmare. This is so hard to work with!

2021-03-27T14:57:12.195700Z

It certainly can be. In this case, as long as you copy all of the pieces of a match result out of a mutable JVM object before using it again, you should be good.

sova-soars-the-sora 2021-03-27T18:45:00.196900Z

would identity be similar to this in other langs?

ghadi 2021-03-27T18:52:45.202200Z

not really - identity is a function, this is a reference/object

1☝️
sova-soars-the-sora 2021-03-27T18:53:54.202800Z

hmmmm

sova-soars-the-sora 2021-03-27T18:54:12.203100Z

maybe i just need to see more examples of identity

sova-soars-the-sora 2021-03-27T18:56:48.204300Z

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

seancorfield 2021-03-27T19:00:10.205500Z

@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).

seancorfield 2021-03-27T19:01:08.205800Z

dev=&gt; (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"}}

1😮
ccortes 2021-03-27T19:25:15.213400Z

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]
  (-&gt; 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.

1🤘
Azzurite 2021-03-27T22:08:19.214900Z

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

seancorfield 2021-03-27T22:08:49.215300Z

(apply hash-map [:a 1 :b 2])

Azzurite 2021-03-27T22:09:34.216100Z

yep, thank you very much! 🙂

seancorfield 2021-03-27T22:09:36.216300Z

If you have a sequence of key/value pairs like [[:a 1] [:b 2]] you can use (into {} [[:a 1] [:b 2]])

hindol 2021-03-27T22:33:30.216500Z

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.

teodorlu 2021-03-27T22:58:23.216700Z

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)

seancorfield 2021-03-27T23:21:59.217100Z

@hindol.adhya It’s based on Java’s built-in Reflection APIs so it’s as “magic” as that 🙂

1👍
Azzurite 2021-03-27T23:49:08.218600Z

what should you do if you have a nice chain with 5 forms where -&gt; works perfectly, but then have one in the middle where you'd need -&gt;&gt;? some stupid thing like (#(func arg1 arg2 %))?

walterl 2021-03-27T23:51:25.218800Z

(-&gt; my-input
    form1
    (-&gt;&gt; map identity)
    form2)

1➕1☝️1