Clojure Tip 💡
name your callbacks
Let’s say you’re using some anonymous functions in your
filters. Here’s some code.
(->> customers (filter #(>= (count (:purchases %)) 3)) ;; only customers with 3+ purchases (map #(apply max-key :total (:purchases %)))) ;; get biggest purchase
This is not a ton of code, but it will make a good example. What happens if we want to name the parts so that the names reflect the intention?
There are two ways to go about it. The first way is to name the steps. The second way is to name the callbacks. I like the second way better.
1. Naming the steps
We could take the
map steps and name them based on their intentions.
(defn select-best-customers [customers] (filter #(>= (count (:purchases %)) 3) customers)) (defn get-biggest-purchases [customers] (map #(apply max-key :total (:purchases %)) customers))
Then we can put the names in place of the
(->> customers select-best-customers get-biggest-purchases)
It makes a compact and clear threading.
2. Name the callbacks
Let’s see what it looks like if we name the callbacks.
(defn good-customer? [customer] (>= (count (:purchases customer)) 3)) (defn biggest-purchase [customer] (max-key :total (:purchases customer)))
Then it looks like:
(->> customers (filter good-customer?) (map biggest-purchase))
Why I like method 2 better
I mentioned before that I liked naming the callbacks better. Here’s why.
First, the threading is not that much harder to read. Most Clojure programmers know
filter (and if they don’t, it’s time to learn them). So this should be an easy thing to read. But, further, the two functions are much more useful. They’re applicable to a single customer, not collections of customers. There are many more things I can do with a function that works on one customer. You can always pass them to
filter later if you need to.
That’s not to mention that the functions that were extracted themselves are shorter and sweeter. They don’t have anonymous functions like the ones from method 1 do.
Well, that’s my opinion, anyway. I think the code speaks for itself. What do you think?
Another episode! This one is my response to Out of the Tar Pit.
Listen and watch here: My response to Out of the Tar Pit.
Clojure Challenge 🤔
Last week’s challenge
The challenge in Issue 383 was to write a function that calculates the iterated square root of a number.
I love the variety of submissions. I think this is a good difficulty level to target.
Please do participate in the discussion on the gist where the submissions are hosted. It’s active and it’s a great way to get comments on your code.
This week’s challenge
There are different ways to express the equation of a line. Here’s one way:
2x + 4y = 1 x + 2y = 1
The x and the y are always the same, but we can sub out variables for the three numbers:
ax + by = c
Now, we can just make a tuple with a, b, and c:
[a b c]
The first two lines represented in this form:
[2 4 1] [1 2 1]
Okay! Now that we have a way to represent lines, your task is to write a function that takes two lines and tells us if they’re parallel. Here’s an example:
(parallel? [2 4 1] [1 2 1]) ;=> true (parallel? [2 4 1] [4 2 1]) ;=> false (parallel? [0 1 5] [0 1 5]) ;=> false ;; lines are not parallel to themselves
I’m looking forward to seeing the variety of answers.
Thanks to this site for the challenge idea where it is considered Medium level in Python.
You can also find these same instructions here. I might update them to correct errors and clarify the descriptions. That’s also where submissions will be posted. And there’s a great discussion!
As usual, please reply to this email and let me know what you tried. I’ll collect them up and share them in the next issue. If you don’t want me to share your submission, let me know.