W1349 Higher Order Functions
Prerequisites[edit]
Coming Soon | |
Lambda Expressions and Closures |
Lamda Expressions[edit]
Lamda expressions (also called "anonymous functions") are essentially the body of a function, i.e. the steps requird to realize a specific algorithm, without begin bound to an identifier. Lambda functions originate from the work of Alonzo Church in the 1930's.
Lamda expressions may contain mutliple symbols, each of which must be bound to a value in order to completely evaluate the expression. Any symbol which has not yet been bound is termed 'free'. In order to bind these free symbols we may rely on the language itself to provide meaning (such as for a literal constant) or we may rely on the surrounding context or environment. An open lambda expression is simply one in which some of the symbols are not yet bound. Such an expression can be closed by providing an environement which supplies definitions for all open symbols; a closure provides this necessary environment.
Hint: In Swift, lambda expressions are called "closures" even if they don't require such an environment.
Many of the functions which we've learned about and used so far are global functions. Essentially, gloal functions associate a name (the name of the function) and a block of code, a lamda expression.
The syntax for definining a named function is as follows:
func addTwo(_ n:Int) -> Int {
return n + 2
}
Note that the actual block of code is located within the braces.
We can create a lamda expression as follows: let f = {(n:Int) -> Int in return n + 2}
However, in order to later reference this lamda expression we'll assign the block of code to a
constant:
This constant behaves much as we'd expect, and we can assign it to another constant if we'd like:
f(3)
Swift provides us with several means of abbreviating the expression. If the type of the expression is known, we can "infer the type from context":
let e : (Int) -> Int = {n in return n + 2} e(4)
In Swift, we're able to take advantage of "shorthand argument names". Each argument begins with a "$" and is numbered consecutively from zero:
let d : (Int) -> Int = {return $0 + 2} d(5)
Swift also allows us to rely on "implicit returns" from single expression closures:
let c : (Int) -> Int = {$0 + 2} c(7)
These shortcuts lead to very concise code. We can now pass these expressions to "higher-order functions", i.e.
functions which accept other functions as parameters. Let's look at a few examples:
1. Sorting
2. Mapping
3. Filtering
// May be used as parameters
// Practical use of closures : Sorting
let a = ["Dill", "Carrot", "Apple", "Banana"]
struct Student {
let name : String let gpa : Float
}
let b = [Student(name:"Nathan", gpa:4.5), Student(name:"Arthur", gpa:4.4), Student(name:"Enig", gpa:5.1)]
Exercises[edit]
Professor Snape needs your help to organize ingredients for a wide variety of potions. You'll need to verify blocks of code to ensure that they're doing exactly what Professor Snape needs. Be careful! Any mistakes can be hazardous to his health. In some cases, more than one answer will be correct.