map with partialλ︎
Lets look at different ways we can map functions over collections with
We can map over a collection of words and increment them by writing an anonymous function.
The anonymous function has a terse form, that removes the boiler plate function definition
(fn ), allowing definition of only the body of a function.
% represents a single argument passed to the function. The
% syntax also supports numbers where there are multiple arguments, e.g.
%2 for the first and second arguments.
%& represents all other arguments and is the same as
(fn [& args]) or
(fn [arg1 & args]).
# character tells the Clojure reader that this is the macro form of a function definition and expands the code to the full form before executing.
Hint::When to use the terse form of anonymous functionλ︎
The terse form is often used with higher order functions, as an argument to a function. If the body of the function is simple to comprehend, then the terse form of anonymous function definition is appropriate. When the body of a function is more complex, then consider using a separate
Returning a Vector instead of a sequenceλ︎
map function returns a lazy sequence. This is very useful for large data sets.
mapv is an eager version of map that returns the result as a vector. This is useful when you require random access lookup in real time.
mapv can also be used to return an eager result if laziness is not required.
Hint::Lists and vectors - does it matter?λ︎
Some functions in
clojure.corewill return a sequence using the list syntax, even if the arguments given are vectors. Most of the time this is not important, as Clojure considers values rather than constructs for most of its functions. For example,
(= ("pig" "cow" "goat" "cat" "dog" "rabbit") ["pig" "cow" "goat" "cat" "dog" "rabbit"])is true as the values are compared rather than the type of container (list, vector)
Adding sheep as an element raises a problem, as the plural of sheep is sheep.
Using a conditional, a test can be added to determine if a name should be made plural
First lets abstract out the anonymous function to a shared function using
def will bind a name to our collection of animals
if function included a conditional test. If that test is true the next expression is evaluated. If the test is false, the second expression is evaluated.
There are several animals that do not have a plural form. Rather than make a complicated test, a collection of animals that are not plural can be defined.
To keep the function pure, we should pass the non-plural-words as an argument
Using the terse form of the anonymous function,
#(), call the pluralise function with two arguments.
map will replace the
% character with an element from the animals collection for each element in the collection.
partial function can be used instead of creating an anonymous function, removing the need for more custom code. The order of the arguments must be swapped for
partial to call
Now we can call pluralise by wrapping it as a partial function.
The argument that is the non-plural-words is constant, its the individual elements of animals I want to get out via map. So when map runs it gets an element from the animals collection and adds it to the call to pluralise, along with non-plural-words
Using partial here is like calling
(pluralise non-plural-words ,,,) but each time including an element from animals where the
Learning at the REPLλ︎
At first I was getting incorrect output,
["deer" "sheep" "shrimp"], then I realised that it was returning the non-plural-words instead of pluralised animals. The arguments from the partial function were being sent in the wrong order. So I simply changed the order in the pluralise function and it worked.
I checked this by adding some old-fashioned print statement.