Fork me on GitHub
#clojure
<
2018-11-05
>
didibus01:11:01

What's the simplest way to have an index inside for? Like I want to know the iteration count. And I don't want to use map-indexed.

seancorfield02:11:06

@didibus And what was the answer?

didibus02:11:56

@seancorfield To wrap things in a map-indexed like so:

(for [[i e1] (map-indexed vector [1 2 3])
       [j e2] (map-indexed vector [:a :b :c])]
  [i e1 j e1])

seancorfield03:11:18

Ah, when you said you didn't "want to use map-indexed" I wasn't sure which way you were going...

didibus03:11:16

Oh right, I guess my constraint was vague. I meant I didn't want to use nested map-indexed, I still wanted to work with for. It makes me curious about the performance though. I think because map-indexed is lazy, there's not really a big impact here.

jaawerth03:11:39

@didibus if you're worried about perf, you could use eduction to stop the unnecessary caching of map-indexed

👍 4
didibus03:11:19

@jesse.wertheim Hum, I had never really understood eduction. So it basically turns a lazy-seq into a kind of generator?

didibus03:11:59

Or maybe more of an iterator

jaawerth03:11:26

@didibus yeah it's a little confusing. It makes a reducible/iterable wrapper and can be used like sequence, but it unlike a lazy-seq it doesn't cache its values - if you save a reference to the eduction and operate on it twice, it will run the transducerse you give it twice for each item. Basically it just ends up being an optimization when you want to make something that's going to be immediately consumed, in which case there's no point to cache it

didibus03:11:45

@jesse.wertheim I see, good to know. And I assume it also avoids the chunking, which can be nice if its used for side effects ?

jaawerth04:11:06

that's the tricky part - it doesn't stop the chunking because that's controlled by the consuming end. fortunately, if that does happen, the chunked part will be cached so you won't end up performing side-effects multiple times in that case

jaawerth04:11:35

for example try (let [foo (eduction (map-indexed #(do (println (format "idx %s val %s" %1 %2)) (vector %1 %2))) [:a :b :c])] [(first foo) (first foo)]) and you'll see things printed twice

jaawerth04:11:04

butt (let [foo (eduction (map-indexed #(do (println (format "idx %s val %s" %1 %2)) (vector %1 %2)) [:a :b :c]))] (first (rest foo))) will only print once

jaawerth04:11:30

the main thing to remember is only to use eduction when you want to generate a reducible/seqable/iterable that is meant to be consumed immediately

didibus04:11:51

I'm still trying to wrap my head around your two examples 😛

didibus04:11:30

But I think I get it. It is cached by the consumer, so if you use the eduction more than once, the side effects will happen over and over again.

didibus04:11:53

But, if you consume a single element of it, you'll get multiple side-effects, since it will consume a chunk of it.

didibus04:11:55

Where as a lazy-seq would similarly have a chunk consumed by a consumer even when requesting a single element, but that whole chunk would have its result cached for other consumers too. Thus consuming the lazy-seq twice would not result in the side-effect happening twice.

didibus04:11:57

So it still makes it probably a bad idea to use eduction for side-effects. At least if control over exactly when and if the side effect executes matters

didibus04:11:37

@jesse.wertheim The funny thing is, the eduction based version seems to be about 40% slower than the lazy one.

jaawerth05:11:27

huh, interesting

jaawerth05:11:31

I'll have to look into that later, lol

jaawerth05:11:45

@didibus ah it looks like doseq coerces things to a chunked-seq so it's probably doing extra work there. another thing you could check is reducing a large eduction vs a large lazy-seq. IIRC that's one place I remember checking the perf difference - that/or a mapcat in a transducer pipeline

petterik18:11:51

eduction nor sequence are currently not taking advantage of chunked-seq optimizations. Eductions are fast to reduce over though. I took a stab at implementing chunked-seq optimizations for eductions and the results were quite satisfactory: https://gist.github.com/petterik/0e0c9bcc4b223c01bbb1442e820ea503

deliciousowl07:11:01

Hey everyone, I want to draw text (.otf font) onto a .png file. What would I use? Quil?

deliciousowl07:11:37

It'll be packaged into a .jar so the fewer dependencies/etc the better

schmee21:11:59

is there a Clojure documentation tool that let’s you have the doc strings separate from the functions?

g21:11:36

hi everyone, what's the best way to serialize and rehydrate a function?

arrdem21:11:56

In general there isn’t one for several reasons. For instance Java object serialization only gets you so far when you have to deal with closing over instance objects. You also have to deal with the environment you “rehydrate” into having to satisfy the dependencies of the environment you “dehydrated” out of. etc.

arrdem21:11:24

The design you’re going for is almost certainly more effort than it’s worth. I’d suggest you rephrase the question in the context of what problem you’re trying to solve with fn serialization.

arrdem21:11:01

That maybe we could help with.

andy.fingerhut23:11:28

There is some Clojure lib from N years ago that can handle some non-tricky cases of this, I think. I have no idea what its restrictions are, not having used it. I only remember it exists because when I learned of its existence, it made me wonder how it implemented what it does: https://github.com/technomancy/serializable-fn

andy.fingerhut23:11:00

Maybe it isn't intended for 'rehydrating' functions at all, only printing

enforser21:11:57

I think you could just add it to the meta data... I'll find an example and confirm it works

schmee21:11:45

I did this, it worked! 🙂

(ns java-http-clj.doc
  (:require [java-http-clj.core :as core]))

(defn add-docstring [var docstring]
  (alter-meta! var #(assoc % :doc docstring)))

(add-docstring #'core/send-async
  "Look, a remotely added docstring!")

arrdem21:11:21

Yeah there are a couple 3rdparty docstrings for core tools that play this game.

arrdem21:11:29

It’s not great IMO - but it definitely works.

schmee21:11:21

out of curiosity, why’s it not great?

arrdem21:11:37

I think there are some regrets around Var metadata - see spec’s use of a separate registry, and Alex’s/Rich’s allusions to maybe task specific registries being better.

schmee21:11:08

ahh, I see. not much one can do about that though

enforser21:11:18

glad to hear it worked - you used the same method as my example was going to be 🙂

arrdem21:11:20

There are a bunch of things which all use Vars as a database and shim keys into metadata.

arrdem21:11:15

Yeah - I guess if you were going to go down this road I’d look at just having some separate lookup structure for your docs and teach that lookup machinery to fall back to :doc.

schmee21:11:39

would that work with tools like Codox though?

arrdem21:11:17

Codox is pretty simple. Patch it to do what you want.

arrdem21:11:58

That seems like a better solution to me than trying to load a bunch of metadata monkeypatching code then running codox.

schmee21:11:31

I’ll take a look!

schmee21:11:27

I don’t think this is really monkeypatching though, I mean the metadata is where regular docstrings go and most people would not consider them anything out of the ordinary 😉

arrdem21:11:40

I consider any amount of non-declarative var / metadata / namespace manipulation monkeypatching 😉

arrdem21:11:53

having spent entirely too much time writing static analyzer code

schmee21:11:42

haha, well, that’s on you for trying to turn Clojure into a static language! 😁

👍 4
arrdem21:11:11

🤷 hard to play any games in the compiler or get much confidence in making changes if you can’t re-analyze declaratively. Lotta regrets there.

slipset21:11:04

on namespaced keywords, is there a shorter or more idomatic way of getting a non-namespaced keyword from a namespaced keyword than:

slipset21:11:22

(keyword (name :user/foo))

emil0r09:11:03

You should be able to deconstruct like this: {:keys [user/foo]}

slipset21:11:59

cool, then I’ll go with that.

arrdem21:11:11

It’s a good snippet.

isak22:11:03

is there a server side hiccup renderer that is more like the reagent rather than the original version?

shaun-mahood22:11:36

Any specifics you are looking for?

isak22:11:04

@U054BUGT4 supporting maps for :style rather than strings, ideally also escaping by default like reagent/react

shaun-mahood22:11:59

I haven't been able to find anything for either of those (I think they're the 2 things I want in a server side renderer, too) - I've moved to using https://github.com/noprompt/garden for CSS which uses maps for styles, and the hiccup2 namespace in [hiccup "2.0.0-alpha1"] to get string escaping. I've heavily considered moving to Rum instead, which has it's own renderer that works in both Clojure and CLJS, but it doesn't do automatic escaping either.

isak22:11:19

ah interesting, thanks for the info