Fork me on GitHub
#clojure-europe
<
2022-04-08
>
RAMart05:04:58

👋 ☀️

dharrigan06:04:29

Good Morning!

plexus07:04:23

Goeiemorgen!

simongray07:04:22

good morning

simongray07:04:48

Working on a Bauhaus-inspired, mildly skeuomorphic aesthetic today for one of my frontends

slipset08:04:46

Trying to be faster, I discovered this little gem https://clojurians.slack.com/archives/C03S1KBA2/p1649401401958449

👀 1
slipset08:04:18

I really dislike these things that seem to work, until they don’t

dharrigan08:04:28

Say you have two lists (of data retreived from a database) and you want one list. Which is more idomatic to use - concat, conj, merge....?

Ben Sless10:04:57

The cheapest, but not most idiomatic solution would be (->Eduction cat [xs ys])

👀 1
Ben Sless11:04:02

pros: cheapest concat you can think of, no risk of lazy sequence explosion, etc cons: results aren't cached

dharrigan12:04:40

Awesome, will give that a whirl!

Jakub Holý (HolyJak)08:04:30

You can rely on Ben to provide a performant answer :) There is a great discussion at https://chouser.us/apply-concat/ (Concat https://stuartsierra.com/2015/04/26/clojure-donts-concat if you have more than 2 colls but you don't).

dharrigan08:04:42

there won't be duplicates, as data is different

dharrigan08:04:15

interesting, I've also discovered (mapcat identity...)

dharrigan08:04:25

into works well too

thomas08:04:20

moring... and TGIF again!!!

🙌 1
genRaiy09:04:00

Good morning

otfrom09:04:13

I like into and cat

otfrom09:04:33

(into [] cat [vec-1 ,,, vec-n])

minimal09:04:44

I like into too

borkdude09:04:35

@minimal so... you're into into. :drum_with_drumsticks:

6
🤡 1
minimal09:04:11

i’m into into too @borkdude

🙏 1
genRaiy09:04:30

concat works … the into [] is only needed if you want to force the resulting collection to be a vector. No?

simongray09:04:57

I would also choose concat. Like @raymcdermott, I only use into when I need to enforce a collection type (or when reifying output from a transducer).

minimal09:04:09

The implementation of the laziness of concat was problematic, can’t remember if it ever got fixed so I tend to stick with into

borkdude09:04:43

laziness never gets fixed

truestory 1
1
borkdude09:04:23

I also use concat, but some awareness around the pitfalls may be good: https://stuartsierra.com/2015/04/26/clojure-donts-concat

1
minimal09:04:45

That’s the article I had in mind

simongray09:04:07

BTW a really nice idiom is (into (empty coll) (f coll)) .

genRaiy09:04:53

bah - if concat has been cancelled, I’m still unreconstructed

simongray09:04:07

#cancelConcat

🔥 1
borkdude09:04:18

or perhaps f can be a transducer (if it has multiple map/filter, etc)

borkdude09:04:05

In Clojure we're doing quite a lot of work that is probably done by compilers in other more sophisticated languages ;)

borkdude09:04:42

(inspired by the latest #defnpodcast with @ben.sless;))

genRaiy09:04:19

It’s the FFS pattern … for f’s sake use a transducer

simongray09:04:32

I don’t use transducers or even parallelisation nearly enough.

otfrom09:04:03

if you still want to be lazy

(sequence cat [[0 1 2] [3 4 5]])
;; (0 1 2 3 4 5)

minimal09:04:32

yeah if you still want concat/mapcat in the mix you can do something over the top with transducers (into [] (mapcat identity) [[1] [2] [3]]) [1 2 3]

borkdude09:04:24

aaand we're back to (into [] cat [[1] [2] [3]])

♻️ 1
Ben Sless10:04:48

Use education or sequence

borkdude10:04:02

educate yourself

😄 1
borkdude10:04:48

that was a joke

borkdude10:04:00

nice podcast btw with defn ;)

otfrom09:04:22

I'm a bit confused about what I've done wrong here:

(sequence cat [0 1 2] [3 4 5])
Execution error (ArityException) at user/eval15916 (REPL:68).
Wrong number of args (3) passed to: clojure.core/cat/fn--8851

otfrom09:04:39

as sequence has & colls as one of its arities

simongray09:04:02

now I am confused

otfrom09:04:11

(sequence (mapcat identity) [0 1 2] [3 4 5] [6 7 8])
Execution error (ArityException) at user/eval15920 (REPL:74).
Wrong number of args (3) passed to: clojure.core/identity

mpenet09:04:26

sequence is like map, so (sequence ... xs xs2 xs3) = (map ... xs xs2 xs3)

mpenet09:04:06

so your fn will be called with as many args as you have sequence arguments minus the xf

otfrom09:04:17

ah, the problem is what I'm passing to mapcat and cat

otfrom09:04:58

(sequence (map (fn [x y z] [x y z])) [0 1 2] [3 4 5] [6 7 8])
;; ([0 3 6] [1 4 7] [2 5 8])

otfrom10:04:33

I was a bit surprised that (sequence cat ...) didn't do that

mpenet10:04:59

I think you are basically asking for (sequence cat [xs1 xs2 xs3])

mpenet10:04:03

it's not shocking to me, it translates nicely from (into cat ...)

otfrom10:04:03

sequence map with multiple collections is doing what I expect it to (getting the first then the second then the third from each collection)

mpenet10:04:00

then (sequence (comp (map (fn [x y z] [x y z])) cat) [0 1 2] [3 4 5] [6 7 8])

otfrom10:04:02

ok, this makes sense to me now at least

(sequence (comp
                 (map (fn [x y z] [x y z]))
                 cat)
                [0 1 2] [3 4 5] [6 7 8])
;; (0 3 6 1 4 7 2 5 8)

wizard 1
reefersleep10:04:15

Good morning! I’ve recently come to realise that it can be hard to talk about the code in Clojure, as I’m pairing with someone essentially completely new to it. What seems simple to me can be troublesome to explain to them.

reefersleep10:04:24

I mean, it’s probably the same for all programming languages. Having the same basic structure in most code, that is, (function-call arg1 arg2), helps a little bit, but there are so many exceptions to that.

reefersleep10:04:54

(I’ve “taught” Clojure to people before, but this is a special case)

RAMart10:04:00

I am experiencing a bit of the opposite: New developers – and that's the difference: New and unbiased – struggle hard with all the stuff you need to know when learning a classic(?) language like Java or C#. Topics we can skip entirely for Clojure.

reefersleep11:04:06

Like objects and classes?

reefersleep11:04:57

I helped my girlfriend when she was doing a course in C#, and she never really understood objects and classes, despite my desperate attempts at coming up with real world analogies 🙂

RAMart12:04:45

Yes, Objects and Classes, this, "By Value" and "By Reference" and based on this: Clone, Shallow Copy, Deep Copy, Shallow Equal, Deep Equal. Value types, reference types, maybe boxing… the list goes on and on.

🔥 1
reefersleep13:04:29

It’s worse than I recall.

reefersleep13:04:53

Yeah, I remember being amazed when I learned Clojure that = just works as you’d expect. That’s incredibly powerful.

RAMart13:04:42

With a single = that is. 🙂 The difference between = , == and === (e.g. in JavaScript) is also something to learn and understand. I try to grow the next generation of developers for over 20 years now. It's really a lot to learn. We – the let's say senior developers – tend to underestimate the sheer amount of knowledge we gained over years.

👍 4
reefersleep09:04:44

I bet! It becomes implicit to our work, especially if you never have to explain it to anyone.

plexus13:04:58

There is nothing wrong with concat. Contrary to into or anything with a transducer concat won't allocate a new collection/sequence. It's just a cheap lazy seq wrapper. And you can reduce that cheaply too. Just don't use it to iteratively stack up collections. apply concat is fine, reduce concat is not.

☝️ 2
👀 1
Jakub Holý (HolyJak)08:04:33

Why is apply fine but reduce is not? Because reduce would nest calls to lazy-seq ending with one per collection, while apply has just a single one?

plexus09:04:40

That's actually a good question 🙂 looking at the implementation I'm not sure, they both seem to generate nested lazy-seqs, but somehow the apply version doesn't exhibit the same stackoverflow behavior

plexus09:04:57

The problem with reduce is that you end up with (concat (concat (concat (concat a) b) c) d). Each wrapping is a lazy-seq, which means that realizing that seqs conumes a stackframe. To get to the first element of a it needs to realize all of the seqs, and thus the stack blows up.

👍 1
plexus09:04:05

Whereas it seems the apply version will only realize the outer lazy-seq, until it actually gets to past the first collection, after which the next lazy-seq gets realized. At least that's my guess after starting at the code for a few minutes 😄

Jakub Holý (HolyJak)12:04:02

I stopped at clojure.lang.IFn#applyTo 😅

plexus13:04:05

Welcome to my ted talk "have you considered not using a transducer?"

trollface 2
😇 2
Ben Sless14:04:22

Not really 😄 Although this is just a private case of "have you considered not writing a staging compiler"