Higher-order functions, Functor and Monad in Swift

I have been writing this post about Functor, Monad and higher-order functions for some time. It started as a post about Monad, but evolved because I think all those 3 concepts are easier to understand when tied together. Understanding one helps to understand the other and so on. I wanted to dig in to this topic because, even if use map and flatMap almost everyday, I find it hard to explain to someone what a Functor or a Monad is.

First time I heard someone explaining a Functor, was back in 2016 AltConf in San Francisco. Daniel Steingberg gave his What the function -talk. To be honest, I didn’t understand much of it. I watched it again few weeks ago and I had the same result, it didn’t really help me to understand the topic any better. Then I watched Daniels talk Why the Func in one of Realms web casts. That talk was a lot more from programming point of view, so it made a lot more sense to me. Even if it wasn’t specifically about Monad, it helped me to understand the topic. I’ve also read numerous blog post, and watched few more talks, so I think have a better idea of how to explain it.

What is a Functor

Let’s start by asking what is a Functor? Functor kind of leads us to Monad. It is also a bit easier concept to understand, which makes it a great place to start. I think of it as a step back from Monad, or the step right before we bump our heads into Monad. The easy answer is: Functor is any type that defines how map is applied to it. Now let’s see what that means.

If you are familiar with Swift I assume that you have been using optionals.

Optional is a wrapper for a value that can be some or none. Basically this means that it either has a value, or that the value is nil. Let’s say we have a function whatIsMyName that takes a String as parameter:

and returns a sentence for example: “Your name is Jimmy”. We want to use this function to set a text to a UILabel, but the string we have at our hands is an Optional. Now, we can use if let or guard to unwrap it:

But it tends to lead to ugly nested code. We cannot use the optionalString since the function does not take Optional as parameter. Inside the if let the string is no longer an Optional so we can use it.

For situations like this, there is a better way: map. The same thing using map looks like this:

This time we got rid of the nesting and the code looks a lot cleaner.

Map is a higher order function. It means that it takes a function or a closure as a parameter or returns a function. To understand what exactly happens here, let’s look at the definition of the map function:

Optional map takes function transform as a parameter. It has a generic type Wrapped which in this case, since we are calling it for optional String, is a String. It also has a Generic type U, which is the type transform function will return. The map function also has a return value U?.

Now, let’s look inside the function. First, we use switch to self. Since this is an extension for Optional self refers to Optional. The enum has 2 cases: somenone. Both cases needs to be handled here. If in fact the Wrapped value contains something, we bind what ever it has inside with the let value binding. Next, we’ll apply the provided function to the value, which turns it to type U. Then we’ll wrap it back inside an Optional and return it.

The nil case is simple, if there is nothing to be unwrapped, map simply returns optional none.

What we accomplished here is that we hid the unwrapping. We take care of it inside the Switch statement, so there is no need to do any nesting. This makes the code easier to read where ever we use the map function.

So Optional is a functor. Functor is any type that defines how map applies to it. In Optional type it defines the behaviour for some and none. Also Sequence, Array and Dictionary are functors.

How does map apply to array

Let’s see how an array works with map. Below you can see 3 different ways to go through array of Int values and duplicate the values inside:

So first we defined a function named timesTwo which doubles the integer value given. In the first example we’ll double the values inside the arrayOfInts using for loop. Second example is the same thing using map and the timesTwo function as a parameter. Third example is when we define the function inside the map closure. All the outputs are the same, but the third one is the cleanest and most expressive of the three.

Map server response to an array of objects

I also wanted to add a bit more specific use case about map so here it comes. When you are working with an app, the app usually makes network requests. The response format usually is JSON, which need to convert to an object using a model. So let’s say you have a service, from which you can get information about your friends. The response is something like this:

An array of friends containing information for you to identify who the particular friend is. JSON is stored in myFriendsJSONArray for later use. The model and it’s constructor looks like this:

As you can see the Address is an Optional, and also a type of it’s own. It’s not a required field since you might not know the home addresses of all your friends.

Model and it’s constructor for Address looks like this:

So this is the basic setup. First let’s check what it looks like to convert the JSON response with traditional for-loop:

We need to create an empty array of friends. Go through the JSON array one by one. Unwrap created friend, since the constructor is nillable. Then append the friend to the myFriends array.

Next, let’s see how the same thing is done using map:

Now we can get the same result with only one line of code. Also this one line is more expressive and clear about what is happening here.

Hmm.. I actually did spoke too soon when I said “the same result”. There is actually one difference between creating array of friends with for-loop and map. As we already discussed map can return an optional. In this case if the response somehow contains broken JSON, for example some key value has changed, nil is returned and stored inside the myFriends array. So when we use map to create array of friends, we get an array of optional friends. That might not be what we aimed, but luckily there is a solution for this: flatMap.

FlatMap flattens the value inside. In the example above, map gives an array of optional friends, which all has a value some or none. Using flatMap instead of map, there values inside the array are longer optionals. Incase the JSON is malformed which would lead to a nil value in one of the array indices, that value is no longer inside the array.

Next, le’t see how flatMap actually works using Optional as an example. And since we are moving to flatMap, we can also start talking about Monad!

What is a Monad?

Monads apply a function that returns a wrapped value to a wrapped value. Now that’s a mouthful. It is a lot easier to say that Monad is a type that defines how flatMap is applied to it. But let’s think a bit more about the first sentence: “Monads apply a function that returns a wrapped value to wrapped value”. Let’s examine the flatMap function with Optional.

FlatMap with Optional

Definition of flatMap function for Optional looks like this:

So we have a wrapped value Optional and we have function that returns a wrapped value (Wrapped) -> U?. First we’ll unwrap the optional inside the switch statement. If a value is available we’ll return the unwrapped value after transform function is applied to it. Incase the wrapped value does not contain anything, we’ll simply return .none.

So we have a function transform that returns a wrapped value U?. Then we define how myFlatMap is applied to the wrapped Optional value. Wait? Wasn’t that the definition of the Monad? Yes it was! Victory! 🙂

Now, let’s see what happens when we use this function:

The nestedOptional is an Optional 10 wrapped inside an Optional. Incase we only print the nestedOptional the output is the Optional(10) inside an Optional. But if we apply the myFlatMap to nestedOptional the output is only Optional(10). So we flattened one layer from the nestedOptional. This is actually exactly what happened with the myFriendsJSONArray.flatMap in the earlier example.

Next, let’s take a look a bit more concrete example with flatMap

FlatMap with Array

First take a look at the definition of flatMap for an array:

Again we have a wrapped value, an Element inside an array, which may or may not contain a value. Basically transform function points to the element inside the array and returns it’s value, which again is Optional. Then we’ll use filter function to filter out all nil values. Lastly, map is used to wrap the value back inside an array. The exclamation mark can be used here, since we have filtered out all the nil values.

Let’s take a look at the friend example again. As you might remember, friend has a value type Address, which is an Optional. We want to list all the addresses from the myFriendsJSONArray input:

If we use map, we’ll have optional values inside the array. One of them contains nil, since we don’t know Timmy’s address. But if we apply the myFlatMap function the nil value will be filtered, since the optional wrapper is flattened:

After myFlatMap we’ll only print out Jimmy’s address, just what we were aiming for!

Conclusion

I think the main reason why people think Monad is such a hard concept to understand, is that “What is a Monad?” is the wrong question. We should be asking: What is an Optional? What are higher-order functions? How is map and flatMap applied to an Optional? How is map and flatMap applied to an Array? All these things are, at least on my opinion, tied together. It’s hard to understand an abstract concept like Monad, without a concrete example. The best thing you can do is to approach the problem step by step: Understand the concept of Optional, then write your own map function for it. Write your own map function for an array. It really helps you to understand these ideas when you write the code yourself.

Incase you want to test the codes in this article, download this playground I have on GitHub.

References

As said, I read a lot of posts before and while writing this article. I wanted to list here the ones that helped me the most. Some of them I read several times and if you find some topics hard, I encourage you to do the same.

Mokacoding – Swift Functors, Applicatives and Monads

Stephan Boyer – Higher-rank and higher kinded -types

Javier Soto – Functors and Monads in Swift

Varvet – Higher order functions in swift

Functional Swift – Higher-Order functions

That was all I wanted to cover in this post! I hope I was able to help you to understand the concepts of Functor and Monad a bit better. Incase you liked this article you might also want to check some of my other posts. Checkout MVVM pattern in Swift or how to write Unit tests for it? Or maybe you might want to know something about Server-side Swift development. Thank you for reading and I hope you have great day my friend!

 

Leave a Comment

Your email address will not be published. Required fields are marked *