Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Syntax and reader by

I suffer a lot from this problem. A function that I repeat the same instructions, depending on the parameters, except for one element (in this case a filter). How can I solve it elegantly?

(defn get-threads
  "Get all urls threads"
    ([]
     (let [comments (distinct (map (fn [comment] { :thread (:thread comment) }) @db))]
   comments))
    ([search]
     (let [comments (distinct (map (fn [comment] { :thread (:thread comment) }) @db))]
   (filter (fn [comment] (s/includes? (s/upper-case (:thread comment)) (s/upper-case search))) comments))))

2 Answers

+1 vote
by

One option is to factor out the common code.

(defn get-comments []
  (distinct (map (fn [comment] { :thread (:thread comment) }) 
    @db))

(defn get-threads
  "Get all urls threads"
    ([] (get-comments))
    ([search]
      (->> (get-comments)
           (filter (fn [comment]
                     (s/includes? (s/upper-case (:thread comment)) 
                                             (s/upper-case search))))

Since functions are so easy to define and compose, it's common to have many small functions you compose to build more sophisticated functions.

by
Thank you very much
+1 vote
by

In this particular case, I'd probably treat a nil value of search as being "always match" in the filter call:

(filter (fn [comment] (or (nil? search)
                          (s/includes? (s/upper-case (:thread comment))
                                       (s/upper-case search))))
        comments)

and then you could just have the 0-arity version of the function call the 1-arity version with nil:

(defn get-threads
  "Get all urls threads"
  ([] (get-threads nil))
  ([search]
   (let [comments ...]
     (filter ... comments))))

Another option here would be to use cond->>:

(cond->> (distinct (map (fn [comment] ...)  @db))
  search
  (filter (fn [comment] (s/includes? ...)))

This will pass the comments into the filter call, only if search is non-nil, else it will return all the comments, unfiltered.

Typically, if I have multiple arities due to optional arguments, I will pick an "empty" value for the optional arguments and just have the lower arities call the full arity, passing those "empty" values -- zero, nil, empty list, etc. Then the full arity version will conditionally handle those "empty" values as appropriate.

by
Very interesting, I hadn't thought of solving it this way. Thank you very much.
...