Fork me on GitHub
Marcio Arakaki02:11:42

Hi Is there an easy whey to group the result of a set of functions into an array ? What I want: (deffn validate [param1 param2 param3] (func1 (validationFunc1 param1) (validationFunc2 param2) (validationFunc3 param1 param2 param3)......)) (validate p1 p2 p3) => [validationFunc1Result validationFunc2Result validationFunc3Result] I'm using juxt right now but the fact that I need to provide all paramters to all functions is making my code unmaintenable


If your functions take different arguments, there's not going to be anything simpler than using juxt with wrappers like I suggested the other day @marcio.akk

Marcio Arakaki02:11:19

I was considering (let [array []] (conj array (validationFunc1 param1) (validationFunc2 param2) (validationFunc3 param1 param2 param3)......) )


or just [ (validationFunc1 param1) (validationFunc2 param2) (validationFunc3 param1 param2 param3) ... ]

πŸ˜„ 4

You can even give them names instead of relying on order in the vector. Will help in maintenance. {:a (validation-fn-a param1) :b (validation-fn-b param1 param2)}

πŸ‘ 4

There must be a prettier way to do this. Original code was (defn get-exam-by-uuid [uuid] (map dissoc-timestamps (repository/get-one-by-uuid uuid))) I needed to run it through one more function, so it became (defn get-exam-by-uuid [uuid] (map add-is-open (map dissoc-timestamps (repository/get-one-by-uuid uuid)))) It works, but is there a better way to apply two functions over a collection than nested maps?


Function composition: comp

user=> (map inc (map #(* % 3) [1 2 3]))
(4 7 10)
user=> (map (comp inc #(* % 3)) [1 2 3])
(4 7 10)


But unfortunately doesn't work in my case. I get "Don't know how to create ISeq from: clojure.core$map$fn__5847".


The major problem here is that I don't know how to debug this code to find out what repository/get-one-by-uuid is returning.


Are you using a REPL?


If so, you can just run that line


Add a few println statements if you need too


If using Cider or Cursive, you can also use their respective debugger


Personally I prefer threading macros for this:

(defn get-exam-by-uuid [uuid]
  (->> (repository/get-one-by-uuid uuid)
      (map dissoc-timestamps)
      (map add-is-open ))


Try a lambda?


(fn [item] (fn2 (fn1 item)))


Lambda gives the same error.


(map f1 (map f2 (...)) still works.


Paste what you're running?


Keep in mind that comp evaluates right-to-left. Maybe your functions are being applied in the wrong order.

Cas Shun17:11:19

if I have a vector of maps like [{:key1 val, :key2 val} {:key1 val, :key2 val} ...] and I want to turn it into a vector of maps containing a single key like [{:key 1 val} {:key1 val} ...], what would be the most idiomatic way to achieve this? I wrote this (map (fn [x] {:key1 (:key1 x)}) [{:key1 1 :key2 2} {:key1 1 :key2 2} {:key1 1 :key2 2}]) and it seems a bit goofy.


map select-keys?


or if you only want a single key, map doesn't help? (map :key1 coll)

Cas Shun18:11:12

@dpsutton I need the original shape but with only a single key

Cas Shun18:11:47

looks like select-keys does what I want


right. i'm questioning if you actually have a need. but if you do actually need a map, then just use select-keys

Cas Shun18:11:26

yeah, the API I'm using requires that shape

πŸ‘ 4
Cas Shun18:11:08

ahh, that's beautiful, thank you πŸ™‚


Is there a "prettier" (less verbose) way to do that than (map #(select-keys % [:key1]) vs)?


That is the most concise way to do it that I know.

πŸ‘ 4
βž• 4

Some people prefer to avoid the #() syntax for defining anonymous functions, and might instead prefer (map (fn [m] (select-keys m [:key1])) vs)


Thanks for confirming. It's not the worst, but I'm clearly just not that used to reading such forms (yet) πŸ˜›


You can break out the function in a let/`letfn` if you find it easier to read that way.


Nah. If there's nothing like that in core, I agree that it'll add more effort than it's worth πŸ™‚


Or if that anonymous function is something they want to use multiple times, to give it a name and use the name there.


Some might even prefer to define that function with a name even if it is only used once -- kinda depends upon preference there -- it can be annoying to pick a reasonable name for something only used once.

πŸ’― 4

I guess I was hoping for a core utility like (map (at1 select-keys [:key1]) vs)


another alternative: (map (fn [{v :key1}] {:key1 v}) vs)


that's kind of weird, I guess, but it seems self describing in a way I like


Where at1 returns a function (fn [x] (select-keys m [:key1])) ? You could write at1 as a Clojure macro if you wanted.


Actually, in the case shown, it could be written as a Clojure function, too...


user=> (defn at1 [f & args]
  (fn [x]
    (apply f x args)))
user=> (map (at1 select-keys [:a]) [{:a 1 :b 2} {:a 3 :b 4}])
({:a 1} {:a 3})


Creating anonymous functions are a 'core utility', and are more general than at1, and I think most Clojure programmers familiarize themselves with it in time.

πŸ’― 4

yeah, I'd get used to it


tiny little DSL-y utility functions add a lot of overhead -- mental overhead


#(select-keys % [:a]) is concise & readable

βž• 4

the specter for it is not bad

user=> (sp/select [sp/ALL (sp/submap [:a])] [{:a 1 :b 1} {:a 2 :b 2}])
[{:a 1} {:a 2}]


it's 100x worse than using clojure.core

Jason Kimmerling18:11:22

Could someone help me with a coding example from a book im reading? I need help dissecting what the reduce portion is actually doing, mainly the "let" portion is highly confusing for me lol.

(def order-details
  {:name "mitchard blimmons"
   :email ""})

(def order-details-validations
   ["Please enter a name" not-empty]
   ["Please enter an email address" not-empty
    "Your email address doesn't look like an email address"
    #(or (empty? %) (re-seq #"@" %))]})

(defn error-messages-for
  "Return a seq of error messages"
  [to-validate message-validator-pairs]
  (map first (filter #(not ((second %) to-validate))
                     (partition 2 message-validator-pairs))))

(defn validate
  "Returns a map with a vector of errors for each key"
  [to-validate validations]
  (reduce (fn [errors validation]
            (let [[fieldname validation-check-groups] validation
                  value (get to-validate fieldname)
                  error-messages (error-messages-for value validation-check-groups)]
              (if (empty? error-messages)
                (assoc errors fieldname error-messages))))

(validate order-details order-details-validations)


There are many ways to slice this kind of pie. I would structure this kind of thing slightly differently. Instead of the values in order-details-validators being vectors with alternating message and predicate, you could instead treat a map with the keys :msg and :valid? as a validator and store a vector of these validators as values in that map. Like this:

(def order-details
  {:name "mitchard blimmons"
   :email ""})

(def order-details-validations
  {:name [{:msg "Please enter a name" :valid? not-empty}]
   :email [{:msg "Please enter an email address" :valid? not-empty}
           {:msg "Your email address doesn't look like an email address"
            :valid? #(or (empty? %) (re-seq #"@" %))}]})
You could then define a function that just applies one validator to a given value returning the error message if invalid. Like this:
(defn apply-validator
  "Applies a validator to a value and returns an error message if invalid
  and nil if valid"
  [value {:keys [msg valid?]}]
  (when-not (valid? value) msg))
The implementation of validate no longer require a raw reduce. You can just take the data for which you have validators (using select-keys), merge it with the validators map through a function that applies all the validators you have (using merge-with), then keep the stuff which is invalid (using remove) and pour it into a map (using into). Like this:
(defn validate
  "Returns a map with a vector of errors for each key"
  [m validations]
  (->> (select-keys m (keys validations))
       (merge-with #(keep (partial apply-validator %2) %) validations)
       (remove (comp empty? val))
       (into {})))
Your original call works as it is:
(validate order-details order-details-validations)
An advantage of doing it this way is, you can add more keys to your validators without breaking anything.


^ Sorry for being so wordy πŸ˜…


This piece is destructuring validation to get at the first two elements of the sequence/vector:

(let [[fieldname validation-check-groups] validation
so it's like (let [fieldname (first validation) validation-check-groups (second validation) ,,, -- does that help @jkimmerling


And the reduce is relying on treating a hash map (`order-details-validations`) as a sequence -- which has pairs of [key value] [key value] (whereas the map is {key value key value}


It would be more idiomatic (and probably less confusing?) to use reduce-kv here:

(reduce-kv (fn [errors fieldname validation-check-groups]
              (let [value (get to-validate fieldname)
                    error-messages (error-messages-for value validation-check-groups)]

πŸ’― 4
Jason Kimmerling18:11:54

@seancorfield that did help quite a bit, thank you!


@bfabry I'm serious. spectre (spelling?) adds complexity on top of what is essentially a function call


it's its own DSL, an additional dependency, and most people (certainly most of #beginners) don't know it


for the most part I agree with you, I just don't think it's great for the community to express that kind of technical argument the way you did

πŸ‘ 4

specter is a load of extra complexity to add to a team/project. unless you happen to be on a team/project that's already happy with it


fair enough. (I'm still not sold on the value prop for spectre)


I can accept that Specter might be "great" for complex, nested data transforms but for a simple case like this it is a) total overkill b) harder to read than all of the core-based suggestions folks made and c) is a whole new learning curve for a declarative (and not very Clojure-y) syntax of its own.


I don't think I've seen a single suggested use of Specter that is directly easier to read than the equivalent core functions so far. Certainly in this channel.

βž• 4

Hi there, please is there a way to temporarily stop logging? Using tools.logging with log back-classic backend, I’m running simulations on a schedule and my log files are getting enormous. Thanks!


What do you mean by temporarily?


Maybe just:

(binding [*logger-factory*


Hi Alex thanks - what I’m trying to do is when my simulation starts I disable all logging, and reenable it at the end. Alternatively disable all logging for all threads started by the simulation trade.


ok, the example above should suffice


Let me try thanks a lot!!


Worked a charm! Thanks so much for the quick answer!


Why does the first expression here not work?


Java methods are not functions. The Math/abs is syntactic sugar around the . special form. See


not only that, but also methods are not first class Objects, so cannot be pushed to the stack, so they cannot be provided as arguments

πŸ‘ 8

For this particular project there will be something like 300 lessons that we're making. What's a decent way to store lots of maps, a vector with index for each collection of lesson maps?


lots of lessons, each lesson has a vec of maps... with many vecs of maps, what is a smart way to index ?

Cas Shun23:11:55

is there a core function that will take a collection, apply a pred to each item, and produce a collection of something like ([truthy-stuff] [falsy-stuff])? Essentially filter that gives you the result and its complement.

Cas Shun23:11:48

reduce seems fairly simple, but I'm curious if there's a better option


in a project.clj, can i have as :resource-paths all directories except one? i’d like to lein uberjar everything in resources/* except one directory that has historically had large files don’t need to be in the jar