Fork me on GitHub

Really struggling with this one, I have a 2d vector with a map inside it which I would like to update with yet another map, something like this:

(update-in [:board i j :a] conj {:b "something"})
But I keep on getting the following error: "Uncaught Error: Vector's key for assoc must be a number." Does anyone know how to do this?


it looks like you're missing the map as the first argument


(update-in the-map-should-go-here [:board i j :a] conj {:b "something"})


if that's not it, I would try pretty printing the map to make sure that a vector didn't sneak it's way in somewhere


Ah, sorry forgot to mention, I'm using (->db ... and then the rest of the code I wrote


if the data structure is too large to print, you can try printing parts of it using get-in , but long term, tools like reveal, rebl, portal, cider inspect can help


ok thank you for helping, i'll figure it out hopefully


another thing to check is to print out [:board i j :a] to make sure that i and j are indeed numbers


tried just now, they are, 0 and 1 for example

👍 1

if instead of {:b "something"} I use a number it works. it will add that number to a vector, no error. Howeve, if I use a string, or a map, or anything than a number - that error occurs


Think I figured it out, the error wasn't happening while writing to structure, it must've been happening while reading from it. I setup second board vector in re-frame db which wasn't connected to anything on frontend and it went through ok without error. Thanks for your help!

🎉 1
Jelle Licht09:10:19

Is there a happy middle between ‘pass your own PRNG to every function’ and simply calling rand, with all the issues w.r.t. being able to test your code? Ideally, I would want to describe properties of my data and invariants that hold regardless of the randomness, but if I compose functions that each depend on this randomness, it quickly becomes hard to make sure to test all code paths.

Lennart Buit09:10:35

Maybe you could use a binding:

(def ^:dynamic *random-source* (Random.))

(def my-random-fn []
  (.nextDouble *random-source*))

Lennart Buit09:10:49

And then in tests, you can control the randomness:

(deftest not-so-random
  (binding [*random-source* (Random. 123)}


you could also directly stub in rand in your tests using with-redefs , eg. (with-redefs [rand (constantly 1)] ...)

Jelle Licht11:10:22

Thanks! with-redefs + properly abstracting why I need randomness allows me to still write tests that I can understand and maintain. For more ‘snapshot’-based testing I can indeed use a constant seed, where I don’t care what the specific outcome is, as long as it is consistent

Alex Miller (Clojure team)12:10:34

We actually have a ticket for something like this in Clojure

👍 1
Jelle Licht13:10:35

I went with a special ns my.project.choices, which has rand -based fns such as go-left?. In my tests, I stub out these choices directly using with-redefs, making writing tests to specifically test the effects of these choices quite easy, without having to care that there might be some silly rand stuff going on behind the scenes.

Muhammad Hamza Chippa10:10:28

I am storing the text in the database on the backend and instead of text I am getting clojure.lang.LazySeq@4426f1d


I would think that what you have there is a sequence of all the results of your db query. You could do something like

(doseq [record results]
    (prn record))
and I imagine it would print out a series of maps containing the text you're looking for. Does that make sense?

Muhammad Hamza Chippa12:10:01

I solved it using (apply str sequence)

Ben Sless12:10:28

There's probably something weird in your implementation How are you storing the text in the DB and how are you reading it back?

Muhammad Hamza Chippa15:10:17

I am reading the text from database using SQL query

Jamison Dance12:10:09

Reading the docs for defn- and it says yielding non-public def. What does non-public mean here? Is it only visible in the same file, or same package, or something else?


same file


though you can always use var to reference it

Johan Thorén13:10:35

Same namespace.


Before I write more own, is there a handy function in Clojure, to “batch a bunch of calls to a fn, based on time”? i.e:

(def f'  (batch 100 f))

(f' 1)  ; called at t 0
(f' 2) ; called at t 50 ms
; // f called with [1 2] 100ms 

(f' 3) ; called at t 200 ms 
; f called with [3] at t 400 ms


since that touches on platform specific details on threading/scheduling/etc and isn't really a common task its safe to assume not


you might be able to find some std lib stuff for splitting stuff into [delay-to-call, args]

Alex Miller (Clojure team)15:10:09

There are some tools in the JDK for this

Alex Miller (Clojure team)15:10:32

java.util.Timer and ScheduleExecutor (fancier)

❤️ 1
Alex Miller (Clojure team)15:10:54

All Clojure fns are Runnable and Callable

❤️ 1

Thanks all, will look deeper!


(defn batch [delay f]
  (fn [args]
    (let [delays (map * (range) (repeat (count args) (/ delay (count args))))]
      (doseq [[delay arg] (map vector delays args)]
        (Thread/sleep delay)
        (f arg)))))

❤️ 1

single threaded version that (might) work

Ben Sless17:10:41

Not a plug but if you're using core.async, I wrote a batch with timeout function which you can use


Aweesome! Thanks team

Michaël Salihi16:10:28

Hello! How is the best approach to transform this following list ("apps" "1" "detail") to ("/apps" "/apps/1" "/apps/1/detail")? I'll tend to go with reduce, right?



Michaël Salihi16:10:52

Thanks, I'll try reductions.


(let [coll ["apps" "1" "detail"]
           join #(str %1 "/" %2)]
 (map join (reductions join "" coll) coll))
("/apps" "/apps/1" "/apps/1/detail")


user> (rest (reductions #(str %1 "/" %2) "" ["1" "2" "3"])) ("/1" "/1/2" "/1/2/3")

Michaël Salihi16:10:11

Awesome. TIL I learn reductions. Thanks to both.