Professional Documents
Culture Documents
FP UNIT 5 Swift
FP UNIT 5 Swift
FP UNIT 5 Swift
When working with Swift, look for the features which fit the functional paradigm and would
help to handle the concurrency better. The code must be expressed more clearly and
expressively, and easily generalize complex problems to create flexible, reusable solutions.
Think in a different way to realize the benefits of functional programming. It’s not just a new
set of tools, it’s a different way of thinking about problems. While learning Swift, “Functional
Thinking” tips are:
1. Avoid Nil, Unless You Mean It
2. Avoid Mutable State
3. Use Higher-Order Functions
var optionalValue:String?
if let s = optionalValue {
// do something with s
}
else
{
// handle the nil value
}
That looks like the if statement checks in Objective-C or other languages, but the key difference
is that it’s explicitly the case that optionalValue may not have a value. Like other functional
languages, Swift also has pattern matching capabilities.
1
Use pattern matching capabilities to deal with Optionals like this:
The Optional binding doesn’t work as well in switch statements as in if statements, and still
requires explicit unwrapping in the where guard clause, but calling out the .None case is a
win for readability. Note that having .None as the first case guarantees that the explicit
unwrapping will not fail in the subsequent cases.
Optionals aren’t strictly a functional feature, but avoiding nil is becoming more popular as
more functional languages come on the scene, and Swift, too, comes out of the box with
these powerful, expressive Optional values. Another way Swift helps us keep things more
explicit and safe is by helping us get a handle on mutable state or avoid it altogether.
2
Immutable arrays don’t allow changes to their length, but do allow values already defined
to be changed.
When passing around these simple data structures, using the immutable versions can help make
code more explicit and deterministic.
.
Swift also has Structures, which, as opposed to objects, are copied by value instead of reference.
This is a possible way to avoid mutating state. Immutable variables and copying by value are
important for dealing with avoiding mutable state, but where the functional paradigm
really gets traction on cutting down on mutation problems is with higher-order functions.
Example: Suppose we wanted to loop through a list of numbers and find their square, or find out
which were odd, or sum them up. We could use a for-in loop and build up some mutable local
variables and do the work. The functional way, however, looks like this:
let numbers = [1,2,3]
let squares = numbers.map { $0 * $0 }
let odds = numbers.filter { $0 % 2 == 1 }
let sum = numbers.reduce(0) { $0 + $1 }
Using Swift’s trailing closure syntax, shorthand argument names, and implicit return syntactic
sugar.
Take notice of a few things here—things crucial to functional thinking:
First, we don’t have any mutable state to worry about. Instead of calculating an answer using
temporary variables, we use functions to give us the answers directly and place these into
constants.
Second, we use methods already on the collections to do the high-level iteration work.
These functions are:
• Map, which produces a new collection with new values for each of the values in another
collection.
• Filter, which returns only the values we specify from a collection.
• Reduce, which turns a collection of values into a single value.
Notice that these definitions don’t specify how the mapping or filtering or reducing is to be done:
they are high-level functions. Using these high-level collection functions, which are common to
almost all functional languages, allows us to separate the problem of iteration—a general
problem—from the specific problem of deriving the answer that we want in particular.
3
The answer we want in particular is derived by passing a closure, but we could just as easily
have passed a function reference. The point is that the heavy lifting is done one item at a time by
a small chunk of composable, reusable functionality that deals with solving a particular problem.
Consider a list of scene titles from Shakespeare’s Romeo And Juliet. There’s an example of a for-
in loop walking through this list to decide if the scene falls into Act 1 or not.
Here’s what that looks like:
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
++act1SceneCount
}
}
This functional solution actually has more lines of code than the procedural one. The benefit to
functional thinking demonstrated here is that reduce handles the iteration part, while the
reusable function countIfAct1 handles the counting logic. Not much in the procedural
approach is reusable. It also requires us to manage our own mutable state, where the functional
approach does not.
By having countIfAct1 be a reusable chunk of functionality, we can start to organize the code
around certain bits of utility that are like this. Maybe those are in objects, maybe they’re in
function libraries. On the other side, by having reduce handle the iteration logic, we hand off that
requirement to the language and compiler. We could possibly gain some benefit from this in the
future, like perhaps a performance benefit if reduce learned to take advantage of multiple cores.
Finally, here’s the same functional approach with a somewhat more readable implementation,
taking advantage of Swift’s trailing closure syntax.
let act1SceneCount =romeoAndJuliet.reduce(0)
{
count, title in title.hasPrefix("Act 1") ? count + 1 : count
}
However, when we get to problems dealing with lists of data, transforming data, deriving
answers from data sets, and so forth, that’s where the functional paradigm really shines.
Languages like Swift that offer a multi-paradigm approach are often the pragmatic way to go
because they give us a variety of tools for different types of problems.
Explore the functional tools of Swift, make functional thinking part of our skill sets, and start
looking at where we can use it to improve how to solve problems, more flexibly, safely, and with
cleaner code.