Higher-Order Functions

Functions that take other functions as parameters are called higher-order functions. One example of such a function is map:

 (map #(* % %) [1 2 3 4 5])
 =>(​1​ 4 9 16 25)

Here we pass in two parameters to the map function. The first parameter is an anonymous function that squares its argument and the second is a collection of numbers. The map function visits each item in the collection and squares it. One advantage of using higher-order functions is that we don’t have to worry about boundary conditions, such as nil checks. The iterator function handles these for us.

Another example of a higher-order function is filter. This function goes through a collection and keeps only the items matching the condition specified.

 (filter even? [1 2 3 4 5])
 =>(​2​ 4)

You can, of course, chain these functions together to solve problems:

 (filter even?
  (map #(* 3 %) [1 2 3 4 5]))
 =>(​6​ 12)

Here we multiply each item by 3, and then we use filter to keep only the even items from the resulting sequence.

Thanks to higher-order functions, you should practically never have to write loops or explicit recursion. When you need to iterate over a collection, use a function such as map or filter instead. Since Clojure has a rich standard library, practically any data transformation can be achieved by a combination of several higher-order functions.

Instead of having to learn a lot of different language features and syntax, you simply have to learn the functions in the standard library. Once you learn to associate data transformations with specific functions, many problems can be solved by simply putting them together in the right order.

Here’s a real-world example of this idea. The problem is to display a formatted address given the fields representing it. Commonly an address has a unit number, a street, a city, a postal code, and a country. We’ll have to examine each of these pieces, remove the nil and empty ones, then insert a separator between them.

Let’s say we have a table in our database that contains the following fields:

 unit | street | city | postal_code | country
 "" | "1 Main Street" | Toronto | nil | Canada

Given the preceding data as strings, we’d like to output the following formatted string:

 1 Main Street, Toronto, Canada

All we have to do is find the functions for the tasks of removing empty fields, interposing the separator, and concatenating the result into a string:

 (​defn​ concat-fields [& fields]
  (​clojure.string/join​ ​", "​ (remove empty? fields)))
 
 (​concat-fields​ ​""​ ​"1 Main Street"​ ​"Toronto"​ nil ​"Canada"​)
 => ​"1 Main Street, Toronto, Canada"

The & notation in the preceding parameter definition states that the function accepts a variable number of arguments. The arguments are represented by a list inside the function body.

Notice that we didn’t have to specify how to do any of the tasks when writing our code. Most of the time we simply say what we’re doing by composing the functions representing the operations we wish to carry out. The resulting code also handles all the common edge cases:

 (​concat-fields​) => ​""
 (​concat-fields​ nil) => ​""
 (​concat-fields​ ​""​) => ​""
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.22.136