Fork me on GitHub
#beginners
<
2018-01-03
>
petr.mensik14:01:34

I bet this problem is simple but I can't really figure out the easiest way to do it. I have a collection like this [{:emails ["first" "second"] :id 1} {:emails ["third"] :id 2}] - basically key/val with option for mutliple emails which is always a collection. And I would like to duplicate the map for each email in it's vector so the result looks like this

[{:id 1 :email "first"}
 {:id 1 :email "second"}
 {:idi 2 :email "third"}]
Any hints where to look? Thanks a lot guys

schmee14:01:48

@petr.mensik this can be done with the sequence fns in clojure.core, here’s one way to do it:

user=> (def a [{:emails ["first" "second"] :id 1} {:emails ["third"] :id 2}])
#'user/a
user=> (mapcat (fn [{:keys [id emails]}] (map #(hash-map :email % :id id) emails)) a)
({:email "first" :id 1} {:email "second" :id 1} {:email "third" :id 2})

petr.mensik14:01:52

@schmee nice, haven't thought about mapcat. Thanks a lot

schmee14:01:58

no problem, mapcat is great to keep in mind when dealing with nested vectors 🙂

gklijs14:01:54

I came up with

(reduce #(into %1 (for [email (:emails %2)] {:id (:id %2) :email email})) [] a)
which gives
[{:id 1, :email "first"} {:id 1, :email "second"} {:id 2, :email "third"}]
not sure which is better..

donmullen14:01:04

If I have a lazyseq that traverses over a very large collection (>14 million items) - does that data accumulate in memory as I do a doseq over it?

schmee14:01:53

@donmullen no, that is what’s meant by “does not retain the head of the sequence” in the docstring: http://clojuredocs.org/clojure.core/doseq

danm14:01:16

Just make sure you doseq instead of doall 😉

donmullen14:01:38

@schmee So in this code - I do have ‘data’ that keeps the head — so likely need to figure a way to not do that?

schmee14:01:00

not sure, are you getting OOM errors with that code?

donmullen14:01:00

yes - just got a GC mem exception about 1/2 way through import

schmee14:01:13

I can’t see anything holding on to the head in there, maybe csv/parse-csv does some shenanigans?

danm14:01:41

Shenanigans? Surely that's the problem

Yuanting16:01:28

Any one know how to make the websocket connection always connect? I can receive a few messages and the connection close.

Yuanting16:01:33

Here is the code

uwo16:01:33

why would (clojure.data.json/read-str (slurp filename)) throw java.lang.StringBuilder cannot be cast to java.io.PushbackReader,?

dpar16:01:33

hi, what is this #_(something)?

dpsutton16:01:53

@teikfaiv it's a reader macro. check https://clojure.org/reference/reader. That particular one ignores the next form at a reader level. It skips that form completely

dpar17:01:31

what does it mean when a function is named like this -main -start?

seancorfield17:01:57

@teikfaiv It generally tells Clojure to generate a Java-compatible function (without the leading -).

seancorfield17:01:29

So when you see (defn -main [& args] ...) that's like a Java main() function.

dpar18:01:30

if I pass to a java method a class generated by gen-class, does it mean that I can forget about running the application from the repl?

seancorfield19:01:54

@teikfaiv Not sure what you mean... can you elaborate?

noisesmith19:01:58

@seancorfield I think the concern is that the class created by gen-class can’t be passed to a method that wants a class if you are loading the code from the repl

noisesmith19:01:33

@teikfaiv if I understand your question correctly, gen-class works even if your namespace is compiled from the repl, as long as you load it from a file (via require or load-file)

noisesmith19:01:44

in fact the clojure repl is the clojure compiler - there’s no separate code path (though there are some things like gen-class that become no-ops if typed directly into a repl instead of being loaded from a file)

admay19:01:38

Hey guys, I have a brain fart on a threading macro, can anyone help me out?

(-> args
     add-foo
     (partial add-bar context))

admay19:01:21

I keep getting a thing back, #object[clojure.core$partial$fn__5563 0x7cb4782b "clojure.core$partial$fn__5563@7cb4782b"]

admay19:01:25

When I’m expecting a map

noisesmith19:01:33

@admay -> is not smart, it’s a thing that fiddles with lists before they are compiled

admay19:01:54

What’s a smarter way to go about it?

noisesmith19:01:13

that form you posted expands to (partial (add-foo args) add-bar context)

noisesmith19:01:38

I’m not saying you aren’t smart for using it, I’m just saying it has no “sense” - it’s just a rote list transform

noisesmith19:01:47

you can use ->> inside -> and skip using partial

noisesmith19:01:06

(-> args (add-foo) (->> (add-bar context))) will do what you want

noisesmith19:01:49

or you can just use (add-bar context (add-foo args)) of course (but I assume this is a placeholder for a more complex expression)

admay19:01:16

> I’m not saying you aren’t smart for using it, I’m just saying it has no “sense” - it’s just a rote list transform Totally did not take it as that! 😄 > but I assume this is a placeholder for a more complex expression Not very complex however theres a good chance of this being expanded to something more complex in the future, i.e.

(-> args
     add-a
     add-b
     add-c
    ...)
So I’m trying to make it a bit easier on the reader in future iterations.

noisesmith19:01:03

yeah - you can use -> on the outside, and alternately use ->> inside as needed to use first position vs. last position of threaded value

noisesmith19:01:37

actually, now that I think of it, (->> args (add-foo) (add-bar context)) works in your case since you never actually need thread-first behavior here

admay19:01:57

(->> args (add-foo) (add-bar context)) This did it! I also just realized that I ought to be using macroexpand to look into these too! Thanks for the help @noisesmith, this helped to clarify a lot about the threading macro behavior!

noisesmith19:01:02

@admay my favorite illustration of how naiive -> is

=> (-> [a 22 b 20] (let (+ a b)))
42

noisesmith19:01:09

don’t write code like that though 😄

noisesmith19:01:57

the threading macros can simplify code a lot but don’t expect them to make sense without your help and guidance

schmee19:01:16

@admay if the standard threading macros become too easy / not confusing enough for others, have a go at https://github.com/rplevy/swiss-arrows 😄

noisesmith19:01:56

a lot of stuff from swiss-arrows is made redundant with things in clojure.core now though as->, some->, cond-> etc.

schmee19:01:50

haha yeah, I wouldn’t recommend anyone to use a library with a function called -<><:p for anything other than educational purposes 😉

noisesmith19:01:28

clearly someone let the perl guys into the party

arrdem19:01:15

hey sometimes you just really want to play s-expression golf

arrdem19:01:32

but yeah I haven’t reached for swiss-arrows since as-> and friends made it into core

noisesmith19:01:57

some-> is under-rated, massively simplifies a lot of my code

arrdem19:01:42

I wish there was a cond-as->, cond->/>> is hugely underrated for composing conditional updates.

noisesmith19:01:50

I should make a version of some-> that has an extra “value to return if we stopped here” expression, then I could use it even more

arrdem19:01:11

I have an entire codebase that’s mostly core.logic.pldb with cond-> to implement the application logic

arrdem19:01:34

@noisesmith sounds like what you really want is an MEmpty that isn’t nil

noisesmith19:01:03

@arrdem I want a value that is specific to the expression - if that’s what that means

noisesmith19:01:20

so I can know in symbolic form which step we had to stop at

noisesmith19:01:28

I was born with an obscure disability that prevents me from ever understanding monads or datomic

noisesmith21:01:54

isn’t this about order of initialization? surely the gen-class created class exists in the repl

dpar21:01:13

gen-class doc says it does nothing when it's not compiling

noisesmith21:01:29

right, and “compiling” is loading something from a file

noisesmith21:01:45

if you didn’t type or copy paste into the repl itself, it is compiling when it loads the code

noisesmith21:01:06

clojure is a compiler, it doesn’t have an interpreter

noisesmith21:01:12

(on the jvm, that is)

dpar21:01:20

well, then I have no idea, lein run returns an error though. While you can uberjar and run it.

hiredman21:01:51

compiling in the gen-class case refers to aot compiling

bronsa21:01:58

yeah no , gen-class only works when aot-compiling

bronsa21:01:10

unfortunately there's no way to use gen-class while JITing clojure

bronsa21:01:22

i think i have a patch in jira to make that work

bronsa21:01:25

it's a 1 line change

hiredman21:01:39

well, you can generate you own bytecode and do whatever whenever

hiredman21:01:23

but clojure won't do it for you unless are aot compiling, for reasons which I think have to do with classloaders and class visbility

noisesmith21:01:23

so from a repl you could call compile right?

bronsa21:01:50

yeah, except compile requires a file to work

hiredman21:01:05

the user experience using compile from the repl is not fantastic

noisesmith21:01:10

oh it can’t use a resource on classpath?

bronsa21:01:54

@hiredman i'm not sure, i think that reason went away in clojure 1.whatever

hiredman21:01:14

compile also has to write the classfiles to disk to a location that is on the classpath

noisesmith21:01:34

I’m coming to the conclusion that questions about gen-class don’t belong in #beginners

bronsa21:01:02

in fact, definterface worked like gen-class and i changed it to generate bybtecode while jiting too

bronsa21:01:18

i forgot to sneak in the change for gen-class too unfortunately

dpar21:01:24

can you think of any workaround to run a javafx app from the repl?

noisesmith21:01:51

there’s fn-fx - I’d solidly bet it’s better than any of the other wrappers you might find

noisesmith21:01:01

and afaik it doesn’t even use gen-class

dpar21:01:10

fn-fx seems abandoned though

hiredman21:01:49

I spent some time poking at javafx for a bit, but that was a while ago, it seemed to make a lot of static assumptions(like exiting the jvm when you closed a window by default) which made it a challenge to work with

noisesmith21:01:00

that other lib you linked to hasn’t seen a commit in the last year

dpar21:01:57

@noisesmith that is just a javafx hello world using plain clojure interop with java

noisesmith21:01:52

anyway, FYI, the author of fn-fx is still very active in the clojure community, and has made a lot of good contributions, I’d be more likely to trust something he wrote than most alternatives (though honestly I have not used fn-fx)

seancorfield21:01:15

@teikfaiv One thing you'll probably have to get used to in the Clojure world is that there are a lot of small, focused libraries that look "abandoned" but are actually stable and functionally complete 🙂

seancorfield21:01:28

(I've not looked at JavaFX but can't you just use proxy and reify to generate objects on the fly to interact with it?)

tbaldridge22:01:12

Yeah, fn-fx isn't abandoned, there simply aren't a ton of people doing JavaFX work in the Clojure community.

hansw23:01:47

or anywhere else for that matter

hansw23:01:52

Suppose I have a lazy seq (which is backed by a java.util.Iterator that is going through a very large file), can i iterate over that seq in batches of size n?

hansw23:01:38

i was looking at take-while but i don't quite get it

hansw23:01:56

or rather, it says pred must be free of side-effects and my iterator is doing I/O and therefore causing side-effects