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.

Reply via email to