Now that you’ve seen how to write your own higher-order functions, let’s take a quick look at a more real-world example.
Imagine for a moment that the
List class doesn’t have its own
map method, and you want to write your own.
A good first step when creating functions is to accurately state the problem.
Focusing only on a
List[Int], you state:
I want to write a
mapmethod that can be used to apply a function to each element in a
List[Int]that it’s given, returning the transformed elements as a new list.
Given that statement, you start to write the method signature.
First, you know that you want to accept a function as a parameter, and that function should transform an
Int into some generic type
A, so you write:
def map(f: (Int) => A)
The syntax for using a generic type requires declaring that type symbol before the parameter list, so you add that:
def map[A](f: (Int) => A)
Next, you know that
map should also accept a
def map[A](f: (Int) => A, xs: List[Int])
Finally, you also know that
map returns a transformed
List that contains elements of the generic type
def map[A](f: (Int) => A, xs: List[Int]): List[A] = ???
That takes care of the method signature.
Now all you have to do is write the method body.
map method applies the function it’s given to every element in the list it’s given to produce a new, transformed list.
One way to do this is with a
for (x <- xs) yield f(x)
for x <- xs yield f(x)
for expressions often make code surprisingly simple, and for our purposes, that ends up being the entire method body.
Putting it together with the method signature, you now have a standalone
map method that works with a
def map[A](f: (Int) => A, xs: List[Int]): List[A] = for (x <- xs) yield f(x)
def map[A](f: (Int) => A, xs: List[Int]): List[A] = for x <- xs yield f(x)
Make it generic
As a bonus, notice that the
for expression doesn’t do anything that depends on the type inside the
Therefore, you can replace
Int in the type signature with the generic type parameter
def map[A, B](f: (B) => A, xs: List[B]): List[A] = for (x <- xs) yield f(x)
def map[A, B](f: (B) => A, xs: List[B]): List[A] = for x <- xs yield f(x)
Now you have a
map method that works with any
These examples demonstrate that
map works as desired:
def double(i : Int): Int = i * 2 map(double, List(1, 2, 3)) // List(2, 4, 6) def strlen(s: String): Int = s.length map(strlen, List("a", "bb", "ccc")) // List(1, 2, 3)
Now that you’ve seen how to write methods that accept functions as input parameters, let’s look at methods that return functions.