I've been working on preparing a kata for performance. Today I had the opportunity to get feedback from my coworkers. One bit of advice I got had to do with applying sequential destructuring to a few helper methods that got extracted during the course of the presentation. (Thanks Gina!) Here are the functions in their original form:
(defn is-strike? [rolls]
(= 10 (first rolls)))
(defn is-spare? [rolls]
(= 10 (+ (first rolls) (second rolls))))
These functions bear some resemblance to the canonical examples in that they access and assign individual elements of a sequence. Clojure destructuring allows a function to bind elements of a collection to named values as it is being received. This saves the developer the inconvenience of defining a let
block or needing to accessing the elements directly every time they are used (which is what the code above does).
Here's how the methods look after applying destructuring:
(defn is-strike? [[first & rolls]]
(= 10 first))
(defn is-spare? [[first second & rolls]]
(= 10 (+ first second)))
These examples don't consume all elements in the provided rolls
collection, so the &
indicates that the un-destructured elements should reside in the named value immediately proceeding it. In the case of these functions, the remaining 'tail' collection is not used, so we needn't assign it a meaningful name:
(defn is-strike? [[first & _]]
(= 10 first))
(defn is-spare? [[first second & _]]
(= 10 (+ first second)))
We've traded complexity in the function body with a bit more definition in the function signature--a fair trade in this case I think.