On Sunday, October 1, 2017 at 5:11:55 PM UTC-4, Scott Barrett wrote: > > Clojure noob, here. I'm very excited to be learning about this language > and becoming a part of this community :) I'm writing a function that works > well, but seems just a bit wrong to me, stylistically speaking. I was > hoping I could get some guidance from you all. > > Here's the code: > > (defn get-if > "Gets the value of a map if exactly one key matches a predicate, > otherwise nil" > ([m predicate?] (get-if nil m predicate?)) > ([found m predicate?] > (if-let [e (first m)] > (let [pred (predicate? (key e))] > (if (not (and pred found)) > (recur (if pred (val e) found) (rest m) predicate?)) > found)))) > > This has gone through a few revisions to get it as concise as possible, > but here are my questions/remarks: > > 1. Is it idiomatic to use if-let to move through a collection the way > I have? In my experience with lispy languages, recursion over sequences > tend to take the form (if (null item) accumlated-value > (recur-over-rest)). This if-let form turns that on its head, which > looks a little backwards at first to me, but it saves a level of > indentation which is generally preferable in my experience. > 2. The main part of this code that's bugging me is the let form, which > is a total hack to keep from testing (predicate? (key e)) twice. Even > still, I have to test the truthiness of pred twice; once in the (not > (and ...)) form and once again in the if of the recur form. I feel > like a clever use of (and ...) or (or ...) would save me here, but I > haven't come upon a solution using those forms yet. > > I like to use multiple recur forms anyway to make clearer the different cases, and I like to use COND to flatten nested IFs:
(defn get-if "Gets the value of a map if exactly one key matches a predicate, otherwise nil" ([m predicate?] (loop [[e & rest] m found nil] (cond (nil? e) found (predicate? (key e)) (when-not found (recur rest (val e))) :default (recur rest found))))) Now you can test end-of-data up front, and by using LOOP for recursion we avoid a lot of noise, including repeatedly passing the predicate. hth, hk > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.