Fork me on GitHub
#clojure
<
2019-01-17
>
wei01:01:47

Could someone explain this result? I thought that the value of an atom is always fully realized (not lazy), so I would expect the pr-str to take much less time.

=> (let [a (atom (take 10 (repeatedly #(Thread/sleep 1000))))]
    (time (pr-str @a)))
"Elapsed time: 10043.797237 msecs"

seancorfield01:01:40

You're deref'ing the atom to get its value -- which is a lazy seq -- and then you're printing it to a string which is realizing the value.

seancorfield01:01:29

So the 10 seconds is the time it takes pr-str to realize the take 10 -- the deref @a would have been near-instantaneous.

seancorfield01:01:12

user=> (let [a (atom (take 10 (repeatedly #(Thread/sleep 1000))))]
         (time @a))
"Elapsed time: 0.007343 msecs"

seancorfield01:01:17

An atom can contain anything -- it's just a container, and it doesn't "do" anything to its contents.

seancorfield01:01:26

^ @wei does that help?

Alex Miller (Clojure team)04:01:34

well, it should only contain immutable values since the swap! function can be applied more than once in the case of concurrent updates

wei04:01:58

@seancorfield I see, so if I want the value to be realized before any derefs, I'd need to do that explicitly, like wrap the computation with doall. thanks for the insight

seancorfield04:01:24

Yes, the same applies to laziness vs eagerness anywhere in Clojure really.

eccentric J07:01:11

I’m thinking of writing a boot task for replacing shortcodes in a markdown file using user-defined functions that return hiccup. Based on other libs I think there should be a defshortcode macro for defining them. How are those handled in other libs? Does it update an atom with a map of properties and a function body?

eccentric J07:01:36

I think data wise it’s important to know the defined shortcodes up front

temco10:01:00

is there any way to run some simple fns inside a clojure jar on android with a much faster startup speed?

victorb10:01:36

how are people dealing with communication between components in stuartsierra/component?

jaihindhreddy11:01:20

Two components can communicate by one of them depending on another and using it. Do you have some other communication in mind?

victorb12:01:49

Well, I might misunderstand something regarding the usage of component... So let's say I have a DB and Web components. The Web component depends on the DB one to do responses with values from the DB. But if I want to change the DB from Web, the state is within DB and cannot be changed from Web.

victorb12:01:53

right now I'm just doing the DB as a simple map that get's stored/load to/from disk. Seemingly, I need to implement this as global state together with the DB component, but then I'm relying on global state...

borkdude12:01:50

The web component has a refererence to the db component, so it can read and write to the DB. I don’t understand your problem.

borkdude12:01:13

A DB is one huge global mutable variable, so that seems OK

borkdude12:01:40

you can model the DB with an atom that has a map in it

drone16:01:00

started trying out spec after having used schema and core.typed. one thing I noticed, compared to core.typed, spec’ing records is kind of laborious and overly verbose. is this something spec proper would ever address (even if just a macro) or should every one fend for themselves and write their own macros? I suppose there’s a third option which is the core team wants to discourage the use of records and/or their use with spec?

Alex Miller (Clojure team)16:01:21

kind of a latent question

Alex Miller (Clojure team)16:01:54

you can spec them as maps with s/keys and :req-un

Alex Miller (Clojure team)16:01:07

there are some ideas we have in spec 2 that might apply better but TBD

drone16:01:34

yep, I have, and it’s gross. =P we wrote a macro to fix that, but curious if the need to write such a macro indicates we’re using Clojure in a way not intended by the core team

drone16:01:37

(or if it’s just because spec is alpha)

Alex Miller (Clojure team)16:01:48

nah, just have never resolved what to do about records

Alex Miller (Clojure team)16:01:10

spec is centered around the idea of semantics associated with (qualified) attributes

Alex Miller (Clojure team)16:01:42

records sit in a weird place with that as the attributes are unqualified but records types themselves are qualified

Alex Miller (Clojure team)16:01:53

we’ve kicked around a bunch of ideas but never got something we liked

drone16:01:06

yeah, exactly part of the pain I was feeling with registering specs for record fields

drone16:01:03

ok, thanks for the info. wanted to make sure I wasn’t missing anything about the design or philosophy of spec

Alex Miller (Clojure team)16:01:17

nope, just some unfinished business

cupello17:01:07

Hi guys, I am in doubt about what is the better way to solve the following problem. Scenario: Base: {:response [{:users [{:id 1} {:id 2}]} {:users [{:id 3} {:id 4}]}]} Path to: [:response :users] Replace with: [[{:id 1, :name "Rafa"} {:id 2, :name "Ana"}] [{:id 3, :name "Jonas"} {:id 2, :name "Leo"}]] Expected: [{:users [{:id 1, :name "Rafa"} {:id 2, :name "Ana"}]} {:users [{:id 3, :name "Jonas"} {:id 2, :name "Leo"}]}] I am thinking about recursion but I would like to know if there is a better way (using something like clojure.walk). Any thoughts?

schmee17:01:07

what does the data structure containing the :names look like?

cupello17:01:30

Sorry, I was not clear in my problem... It is not a fixed structure. It's like this: Given a base, path and "Replace with data", return base replaced with data

schmee17:01:41

i.e (assoc-in original-data [:response :users] new-data)

cupello17:01:31

The problem with using assoc-in is that the path don`t know if some key, like :users, is a list or not.

schmee18:01:10

okay, now I see what you mean. is this part of a larger example? otherwise it might be easier to wrap the new data structure in :users:

(def new (mapv #(hash-map :users %) new-data))
and then (assoc old-data :response new)

schmee18:01:15

is :id unique?

cupello18:01:36

:id is just a key... Could be anything and could not exist. I am trying now to manipulate the path. So, using the previous example, generate something like: [:response 0 :users] and [:response 1 :users]

schmee18:01:32

I highly recommend Specter for things like this: https://github.com/nathanmarz/specter/

schmee18:01:46

here’s an example:

user=> m
{1 {:id 1, :name "Rafa"},
 2 {:id 2, :name "Ana"},
 3 {:id 3, :name "Jonas"},
 4 {:id 4, :name "Leo"}}

user=> base
{:response [{:users [{:id 1} {:id 2}]} {:users [{:id 3} {:id 4}]}]}

user=> (transform [:response ALL :users ALL] #(get m (:id %)) base)
{:response [{:users [{:id 1, :name "Rafa"} {:id 2, :name "Ana"}]}
            {:users [{:id 3, :name "Jonas"} {:id 4, :name "Leo"}]}]}

schmee18:01:08

basically, for problems like this the details matter: exactly what the input is, what the data you want to place there instead etc. determines what the best approach is

schmee18:01:55

but for the general problem of “replace something in a nested data structure with something else” Specter is IMO the way to go 🙂

cupello18:01:08

Nice! Thank you! I will give it a shot =D

rutledgepaulv19:01:49

(clojure.walk/postwalk-replace (into {} (juxt #(select-keys % [:id]) identity) replacements) base)

benoit20:01:02

You can definitely look at specter but to modify nested data structures in clojure using the "core library" you also have zippers. It takes a bit of playing around to get used to them (if you're not already) but once you know them you will be able to apply them in many scenarios.

benoit17:01:08

@lucelios It looks like you want to join on the :id attribute. See https://clojuredocs.org/clojure.set/join

cupello17:01:08

Nice! Thank you very much. But Can I use it lists that have maps and lists... ?

borkdude21:01:40

The changelogs of Clojure only go back to 1.3. I want to know if I remember this correctly: binding was allowed to rebind any var instead of only dynamic vars in the early versions of Clojure. Later on you could only do that with dynamic vars. with-redefs was introduced for rebinding the root values of vars e.g. for testing. Was that related to the change to binding?

Alex Miller (Clojure team)21:01:08

by which I’d say, yes

lwhorton22:01:16

is there a nice idiomatic way to take a vector of maps [{:a 1 :b 2} {:c 3 :d 4}] and turn it into a map based off some key in the vec’s map? {1 {:a 1 :b 2} 3 {:c 3 :d 4} ...?

lwhorton22:01:31

obviously a reduce would work, but it feels icky

lwhorton22:01:14

(reduce #(assoc %1 (:the-key %2) %2) {} the-vec)

lwhorton22:01:28

(now i see that the above is confusing, assume each map entry in the vector has the same keys)

dpsutton22:01:27

(into {} (map (juxt :a identity)) coll)

lwhorton22:01:18

interesting … seems weird to juxt with an identity, but necessary because of how into works I assume? takes [k v] pairs

dpsutton22:01:51

yes you want a sequence of [(:a thing) thing] as your key value pairs which will go into the map

lwhorton22:01:03

! group-by is exactly it, thanks @hiredman

borkdude22:01:13

well, it seems you assume that the vector of maps has a unique value for the same key in each map?

lwhorton22:01:30

yes, i do — which fits for this particular dataset

lwhorton22:01:43

good heads-up thinking though

borkdude22:01:53

so then it’s slightly different than group-by. we have a function called index-by for that, I can look it up

borkdude22:01:32

(defn index-by
  "Returns a map which indexes values by the result of calling kfn
  with given value."
  ([kfn values]
   (index-by kfn values nil))
  ([kfn values flat?]
   (tzipmap (map kfn values) values flat?)))

borkdude22:01:53

(where tzipmap is a transient-based version of zipmap)

dpsutton22:01:56

i think the (into {} (map (juxt :a identity)) coll) will use transients for free because of into

borkdude22:01:42

could be, this code probably stems from before transducers ,etc.

noisesmith22:01:15

there's the similar clojure.set/index as well - allows multiple relations to index and multiple matches for each value of the index

noisesmith22:01:50

egret.run=> (clojure.set/index [{:a 0 :b 1} {:a 1 :b 1}] [:a])
{{:a 0} #{{:a 0, :b 1}}, {:a 1} #{{:a 1, :b 1}}}

lwhorton22:01:16

i love clojure.set, i use it almost everywhere

lwhorton22:01:31

its so much easier for me to think about data as just sets and joins/unions/etc

lwhorton22:01:20

woah. that’s a great idea for a tool…

lwhorton22:01:17

where has this been all my life

borkdude22:01:12

set/index comes up first when you use [{:a 1} {:a 2}] [:a] as the args.

jmckitrick23:01:18

I’m spinning up some old projects with lein repl and getting this error:

jmckitrick23:01:21

No such var: nrepl.transport/uri-scheme

jmckitrick23:01:47

I have lein 2.8.3, clojure 1.8.0

jmckitrick23:01:58

I clearly have something out of sync somewhere

dpsutton23:01:00

downgrade to lein 2.8.1 and try

dpsutton23:01:10

yes | lein upgrade 2.8.1

noisesmith23:01:45

yeah - lein changed nrepl versions with a recent release, and that could break old projects if they or their middleware relied on the way nrepl used to work

borkdude23:01:51

maybe you have some incompatible nrepl in your profiles.clj?

noisesmith23:01:20

it could break all your projects if your profiles.clj pulled in a middleware for the old nrepl

jmckitrick23:01:35

Yes, I was hoping to use an older project to do some cider hacking. And it’s complaining about middleware as well. I feel a bit lost, lol.

jmckitrick23:01:41

Everything used to just work

jmckitrick23:01:51

I’m sure the new stuff is great, of course 😉

noisesmith23:01:07

well, the CIDER maintainer also maintains nrepl, so they should at least evolve together now

jmckitrick23:01:20

ok, I have a repl… that’s good…. now let’s try cider….

jmckitrick23:01:23

Hmm. So for CIDER… can I upgrade the deps and the latest CIDER while keeping lein at 2.8.1?

dpsutton23:01:25

no unfortunately. CIDER was straddling both tools.nrepl and nrepl/nrepl through 0.19 but the most recent 0.20 dropped tools.nrepl support. now the entire application needs to be newer nrepl throughout

jmckitrick23:01:24

So… if I want to make the leap… is there an upgrade guide?

dpsutton23:01:05

we can chat in #cider but just check your deps for tools.nrepl.

jmckitrick23:01:31

Cool, thanks!