I like Erlang, though I can’t claim to be proficient in it. I haven’t even written a “real” program in Erlang yet, but I still enjoying working with it. The other night I was going back through the excellent online book Learn You Some Erlang for Great Good and started working with list comprehensions. In short, a list comprehension in Erlang is about “building sets from sets.” Observe:
1 |
[2*N || N <- [1,2,3,4]]. |
This whacky looking code takes the list [1,2,3,4]
and creates a new list by binding each element to the variable N
, and then applying the function 2*N
. The result is a new list: [2,4,6,8]
. You can even do something like convert an array of temperatures given in Celsius to Fahrenheit:
1 2 3 |
[C*(9/5)+32 || C <- [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]. [32.0,50.0,68.0,86.0,104.0,122.0,140.0,158.0,176.0,194.0, 212.0] |
Slick. Of course, this is a Swift tutorial, so obviously you can do the same thing in Swift, and let’s face it, in a much more readable syntax:
1 2 3 4 |
var temperatures:Array<Double> = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] temperatures.map({(c: Double) -> Double in return c*(9/5)+32 }) |
Granted, this is a bit more verbose than the Erlang example, but if you’ve read any of our other posts you will know we’re a big fan of verbose (also known as readable) code. For those that appreciate a bit more compact form though, you can do:
1 |
temperatures.map({c in c*(9/5)+32}) |
The second form is a “single statement closure” that implicitly returns the value of its only statement, and we can omit naming the parameter type and return type. The parameter type is implied as Double
since we are mapping over an Array<Double>
. Our return type will be promoted to a Double
as well.
Of course we aren’t limited to numbers here, we can supply an array of tuples of Point
s and output the distance of each point from the origin (0.0, 0.0).
[objc]
import Foundation
typealias Point = (x:Double, y:Double)
var points:Array<Point> = [(1,1), (1,2), (-1,-1), (-1,-2)]
println (points)
var distances = points.map({
(x,y) in sqrt(pow(x,2) + pow(y,2))
})
println(distances)
[/objc]
Note the elegance in (x,y) in
. Each tuple element yielded to our closure is bound to (x, y)
, thus allowing us to calculate the distance of the point from the origin using the standard [math]d=\sqrt{(x^2 + y^2)}[/math] formula.
Of course, we aren’t limited to using Array.map
with just numbers, you can operate on any data type you like.
map
isn’t the only nifty Array
function. Take a look a this Erlang code (we’re borrowing the example from Learn You Some Erlang):
1 2 |
[X || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0]. [2,4,6,8,10] |
Once again, Erlang takes the top prize for odd-looking syntax. The [X || X <- [1,2,3,4,5,6,7,8,9,10]
looks familiar, but it's followed by , X rem 2 =:= 0].
. This is secret code for "supply only elements that are divisible by 2" thus the right half after the comma is a filter. Well, Swift can filter too!
1 2 3 4 5 6 7 |
$ swift -repl Welcome to Swift! Type :help for assistance. 1> [1,2,3,4].filter({x in x % 2 == 0}) $R1: Int[] = size=2 { [0] = 2 [1] = 4 } |
Very handy. We can also chain map
and filter
, like this:
1 2 3 4 5 6 7 8 9 |
2> import Foundation 3> [1,2,3,4,5,6,7,8,9,10].filter({x in x % 2 == 0}).map({x in pow(x,2)}) $R7: CDouble[] = size=5 { [0] = 4 [1] = 16 [2] = 36 [3] = 64 [4] = 100 } |
This code filters out the odd numbers from the array and then squares the remaining items. Or put another way it squares even numbers between 1 and 10.
The Swift Array
generic (yes, it's a generic) has a number of other hidden gems. Be sure and check out the Swift Standard Library Reference for more information.
Now, if only Swift would incorporate Erlang's bit syntax. That would be cool.
Editors Note: You may notice we don't show examples in the Xcode playground but rather use the Swift REPL interpreter from the command-line. For details on how to do this see our previous post.