PurelyFunctional.tv Newsletter 384: name your callbacks
Issue 384 - June 29, 2020 · Archives · Subscribe
Clojure Tip 💡
name your callbacks
Let's say you're using some anonymous functions in your map
s and
filter
s. 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 filter
and 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 map
and filter
steps.
(->> customers
select-best-customers
get-biggest-purchases)
It makes a compact and clear threading.
2. Name the callbacks
Okay, I'm calling them callbacks because I've been writing a lot of
JavaScript recently. But seeing as we don't have a better name (do we?),
I'm going to call the function argument to map
and filter
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 map
and 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 map
and 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?
Podcast episode🎙
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
parallel lines
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.
Rock on!
Eric Normand