Advent of Code 2018, Day 6 was much more involved than the previous 2018 puzzles. There's lots of grid work. Concurrent with my work on this puzzle I was reading the Clojure Style Guide and was struck by the guidance on favoring the partial
function over anonymous predicates.
For convenience, I'll post the example here:
;; good
(map #(+ 5 %) (range 1 10))
;; (arguably) better
(map (partial + 5) (range 1 10))
The 'good' example defines an anonymous function with #(+ 5 %)
, which is equivalent to (fn [x] (+ 5 x))
.
The '(arguably) better' example defines an anonymous function with (partial + 5)
, which is equivalent to (fn [& xs] (apply + 5 xs))
.
There are two things I like about the partial
approach compared to the #(... %)
approach:
map
as in (map (partial + 5) (range 1 10) (range 1 10))
.There are a few things I don't like about the partial
approach:
#(... %)
#(... %)
since you have to envision the extra parameter(s) (%
) yourself.I'd like to contrast these two approaches with some of the code from the puzzle at hand. There are two functions being invoked in predicates:
(defn infinite? [landmarks location] #_"implementation omitted")
(defn closest [landmarks location] #_"implementation omitted")
Here's how it looks with partial
predicates:
(defn calculate-areas [arena landmarks]
(as-> (map (partial closest landmarks) arena) $
(remove nil? $)
(map last $)
(remove (partial infinite? landmarks) $)
(frequencies $)))
Here's how it looks with #(... %)
predicates:
(defn calculate-areas [arena landmarks]
(as-> (map #(closest landmarks %) arena) $
(remove nil? $)
(map last $)
(remove #(infinite? landmarks %) $)
(frequencies $)))
I'm on the fence. Which do you prefer?
-Michael Whatcott