First-class functions
First-class functions allow us to make new functions by providing our base functions with function parameters. In the following code, our base function is Filter. By passing ByMake("Toyota") to Filter, we remove most of the car items from our collection, leaving only Toyota:
cars := Filter(ByMake("Toyota"))
We also have the ability to transform any function that works on single elements into a function that works on lists, by wrapping it with the Map function. Without our new functional style of programming, we might be tempted to implement a for loop and apply the fmt.Sprintf transformation on each inpidual car, as follows:
// cars: Honda Accord, Honda Accord ES2, Lexus IS250, Honda CR-V, Lexus SC 430,...
for _, car := range cars {
thisCar := fmt.Sprintf("%s %s", car, map[string]string{
"Honda": "LX",
"Lexus": "LS",
"Toyota": "EV",
"Ford": "XL",
"GM": "X",
}[GetMake(car)])
// upgrade a car by appending "LX" ... to the end of the model name
mappedCars = append(mappedCars, thisCar)
}
// mappedCars: Honda Accord LX, Honda Accord ES2 LX, Lexus IS250 LS...
Instead, we can simply pass the Upgrade function to Map as we compose our data transformation:
Filter(ByMake("Toyota")).Map(Upgrade())
We no longer need to write for loops that manipulate arrays because we can call Map inline.
HOFs can greatly reduce the time that it takes to develop complex logic. We can quickly compose smaller, task-specific functions into solutions for complex business logic much faster, with less scaffolding code, which means we'll have fewer bugs to fix. Our functions are in essence reusable building blocks.
HOFs are independent, making them easy to reuse, refactor, and reorganize in our code base. This makes our programs more flexible and resilient to future code changes.
More readable code, faster implementation, fewer bugs. The benefits of FP are adding up!