Fork me on GitHub
Jeff Evans03:05:43

Is it considered bad form to nest -> inside cond-> like this? Suppose I want to both assoc some keys and dissoc some keys if the map contains :a (and perhaps even do more things) Is there a better way of expressing this?

(let [my-map {:a 1 :b 2 :c 3}]
  (cond-> my-map
    (:a my-map) (->
                 (assoc :x 8 :y 9 :z 10)
                 (dissoc :b))))


I do it often. The other option is to repeat the same condition which is harder to read imo.

👍 2

seems ok to me

Ben Sless06:05:31

Aren't threading macros designed to be composed this way? Or was it just a happy accident?


@UK0810AQ2 the threading macros are designed to nest inside -> , in this case I think if is more readable / idiomatic

(let [my-map {:a 1 :b 2 :c 3}]
  (if-not (:a my-map)
     (->> my-map
          (assoc :x 8 :y 9 :z 10)
          (dissoc :b))))


but the first example is OK

Jeff Evans17:05:08

yeah I was thinking more where there were potentially multiple “rules” that should apply. the nice thing about cond-> is that all matching branches will happen, unlike cond

Jeff Evans17:05:47

though I suppose at a certain point it could be argued that needs to be broken up into different fns


oh yeah, definitely use cond-> if there are more than one conditional


Am not sure what kind of function should I be using. Do I use reduce or do I have to loop through the sequence ?


Okay I think I understand that reduce should work. But for more complicated cases like this it can be quite difficult to reason about :thinking_face:


the thing that made reduce / fold click for me was realizing that it is a direct translation of a for loop across a collection, with the nuance that you pass an immutable value forward to each iteration (with reduced allowing for early exit). note that if you need multiple values to be carried across elements ("updated for each cycle of the loop") you can easily use a hash-map as the accumulator and pull out the interesting values on exit