Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Functional Swift
Search
Chris Eidhof | @chriseidhof
August 07, 2014
Technology
1
150
Functional Swift
Łódź wiOSłuje - August, 2014
Chris Eidhof | @chriseidhof
August 07, 2014
Tweet
Share
More Decks by Chris Eidhof | @chriseidhof
See All by Chris Eidhof | @chriseidhof
Dutch FP Day 2015
chriseidhof
2
380
Tiny Networking in Swift
chriseidhof
2
19k
Functional Swift - Brooklyn
chriseidhof
3
1.2k
Functional Swift - SF
chriseidhof
6
26k
Functional Swift
chriseidhof
6
1.3k
Functional Programming in Swift
chriseidhof
40
19k
Lighter View Controllers
chriseidhof
4
200
Parsing with Blocks
chriseidhof
2
230
Practical Concurrent Programming
chriseidhof
4
280
Other Decks in Technology
See All in Technology
DevIO2025_継続的なサービス開発のための技術的意思決定のポイント / how-to-tech-decision-makaing-devio2025
nologyance
1
400
なぜスクラムはこうなったのか?歴史が教えてくれたこと/Shall we explore the roots of Scrum
sanogemaru
5
1.6k
AI時代を生き抜くエンジニアキャリアの築き方 (AI-Native 時代、エンジニアという道は 「最大の挑戦の場」となる) / Building an Engineering Career to Thrive in the Age of AI (In the AI-Native Era, the Path of Engineering Becomes the Ultimate Arena of Challenge)
jeongjaesoon
0
160
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
9
73k
ハードウェアとソフトウェアをつなぐ全てを内製している企業の E2E テストの作り方 / How to create E2E tests for a company that builds everything connecting hardware and software in-house
bitkey
PRO
1
150
KotlinConf 2025_イベントレポート
sony
1
140
「何となくテストする」を卒業するためにプロダクトが動く仕組みを理解しよう
kawabeaver
0
410
250905 大吉祥寺.pm 2025 前夜祭 「プログラミングに出会って20年、『今』が1番楽しい」
msykd
PRO
1
940
【NoMapsTECH 2025】AI Edge Computing Workshop
akit37
0
190
roppongirb_20250911
igaiga
1
240
MCPで変わる Amebaデザインシステム「Spindle」の開発
spindle
PRO
3
3.3k
バイブスに「型」を!Kent Beckに学ぶ、AI時代のテスト駆動開発
amixedcolor
2
560
Featured
See All Featured
Building Applications with DynamoDB
mza
96
6.6k
jQuery: Nuts, Bolts and Bling
dougneiner
64
7.9k
The Art of Programming - Codeland 2020
erikaheidi
56
13k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
Bash Introduction
62gerente
615
210k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
13k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Git: the NoSQL Database
bkeepers
PRO
431
66k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Transcript
Functional Swift @chriseidhof Łódź wiOSłuje - August, 2014
What's Functional Programming? • Pure • Referentially transparent • Typed
Our data set let cities : [String:Int] = [ "Warszawa":
1706624 , "Kraków": 766583 , "Łódź": 753192 , "Wrocław": 632930 , "Poznań": 567932 ] let names = Array(cities.keys) let populations = Array(cities.values)
Names > [Poznań, Warszawa, Wrocław, Kraków, Łódź]
Populations > [567932, 1706624, 632930, 766583, 753192]
Map func addCity(s: String) -> String { return s +
" is a city" } names.map(addCity) > [Poznań is a city, Warszawa is a city, Wrocław is a city, Kraków is a city, Łódź is a city]
Filter func isLodz(s: String) -> Bool { return s ==
"Łódź" } names.filter(isLodz) > [Łódź]
Filter, simplified names.filter({ (s: String) -> Bool in return s
== "Łódź" }) > [Łódź]
Filter, more simplified names.filter({ s in return s == "Łódź"
}) > [Łódź]
Filter, even more simplified names.filter({ return $0 == "Łódź" })
> [Łódź]
Filter, simplest names.filter { $0 == "Łódź" } > [Łódź]
populations.filter { $0 > 1000000 } > [1706624]
Sum of an array func sum(arr: [Int]) -> Int {
var result = 0 for i in arr { result += i } return result } sum(Array(1..<10)) > 45
Product of an array func product(arr: [Int]) -> Int {
var result = 1 for i in arr { result *= i } return result } product(Array(1..<10)) > 362880
Reduce func reduce(initialValue: Int, combine: (Int,Int) -> Int, arr: [Int])
-> Int { var result = initialValue for i in arr { result = combine(result,i) } return result }
Reduce reduce(0, +, Array(1..<10)) > 45 reduce(1, *, Array(1..<10)) >
362880
Sum and Product let sum = { reduce(0,+,$0) } let
product = { reduce(1,*,$0) }
Concatenate func concat(strings: [String]) -> String { var result =
"" for x in strings { result += x } return result } concat(names) > PoznańWarszawaWrocławKrakówŁódź
Generics func reduce<A>(initialValue: A, combine: (A,A) -> A, arr: [A])
-> A { var result = initialValue for i in arr { result = combine(result,i) } return result } reduce("", +, names) > PoznańWarszawaWrocławKrakówŁódź
Adding line-breaks reduce("", { $0 + "\n" + $1 },
names) > Poznań > Warszawa > Wrocław > Kraków > Łódź
Making reduce more generic func reduce<A,R>(initialValue: R, combine: (R,A) ->
R, arr: [A]) -> R { var result = initialValue for i in arr { result = combine(result,i) } return result }
Example: Core Image
The Objective-C way CIFilter *hueAdjust = [CIFilter filterWithName:@"CIHueAdjust"]; [hueAdjust setDefaults];
[hueAdjust setValue: myCIImage forKey: kCIInputImageKey]; [hueAdjust setValue: @2.094f forKey: kCIInputAngleKey];
A Swift Filter typealias Filter = CIImage -> CIImage
Blur func blur(radius: Double) -> Filter { return { image
in let parameters : Parameters = [kCIInputRadiusKey: radius, kCIInputImageKey: image] let filter = CIFilter(name:"CIGaussianBlur", parameters:parameters) return filter.outputImage } }
Example let url = NSURL(string: "http://bit.ly/1pabRsM"); let image = CIImage(contentsOfURL:
url) let blurBy5 = blur(5) let blurred = blurBy5(image)
None
Color Generator func colorGenerator(color: NSColor) -> Filter { return {
_ in let filter = CIFilter(name:"CIConstantColorGenerator", parameters: [kCIInputColorKey: color]) return filter.outputImage } }
Composite Source Over func compositeSourceOver(overlay: CIImage) -> Filter { return
{ image in let parameters : Parameters = [kCIInputBackgroundImageKey: image, kCIInputImageKey: overlay] let filter = CIFilter(name:"CISourceOverCompositing", parameters: parameters) return filter.outputImage.imageByCroppingToRect(image.extent()) } }
Color Overlay func colorOverlay(color: NSColor) -> Filter { return {
image in let overlay = colorGenerator(color)(image) return compositeSourceOver(overlay)(image) } }
Combining everything let blurRadius = 5.0 let overlayColor = NSColor.redColor().colorWithAlphaComponent(0.2)
let blurredImage = blur(blurRadius)(image) let overlaidImage = colorOverlay(overlayColor)(blurredImage)
None
Combining everything, take 2 let result = colorOverlay(overlayColor)(blur(blurRadius)(image))
Filter composition func composeFilters(filter1: Filter, filter2: Filter) -> Filter {
return {img in filter1(filter2(img)) } }
Using filter composition let myFilter1 = composeFilters(blur(blurRadius), colorOverlay(overlayColor)) let result1
= myFilter1(image)
Filter composition with an operator infix operator |> { associativity
left } func |> (filter1: Filter, filter2: Filter) -> Filter { return {img in filter1(filter2(img))} }
Using filter composition let myFilter2 = blur(blurRadius) |> colorOverlay(overlayColor) let
result2 = myFilter2(image)
Function composition func |> (f1: B -> C, f2: A
-> B) -> A -> C { return {x in f1(f2(x))} }
Example: Spreadsheet
None
None
None
Expressions enum Expression { case Number(Int) // e.g. 10 case
Reference(String,Int) // A0 case BinaryExpression(String,Expression,Expression) // 1 + A9 case FunctionCall(String,Expression) // SUM(...) }
Parsing references let reference = { Token.Reference($0,$1) } </> capital
<*> naturalNumber
Parsing expressions prim = numberOrReference <|> functionCall <|> parens(expression)
Parsing expressions let operators : [[String]] = [ [":"] ,
["*", "/"] , ["+", "-"] ] let expression = pack(operators, prim)
Parsing results We can now convert this: parse(expression, "SUM(A1:A9)") into
this: Expression.FunctionCall("SUM", Expression.BinaryExpression( ":", Expression.Reference("A",1), Expression.Reference("A",9) ) )
Evaluating expressions
The result enum enum Result { case IntResult(Int) case StringResult(String)
case ListResult([Result]) case EvaluationError(String) }
The evaluation function func evaluate(expressions: [Expression?]) -> [Result] { return
expressions.map(evaluateExpression(expressions)) }
Evaluating an expression evaluateExpression([42,10*10,A0+A1])('A1') > 100 evaluateExpression([42,10*10,A0+A1])('A2') > 142
Evaluating an expression func evaluateExpression(context: [Expression?]) -> Expression? -> Result
{ return {e in e.map { expression in let compute = evaluateExpression(context) switch (expression) { case .Number(let x): return Result.IntResult(x) case .Reference("A", let idx): return compute(context[idx]) case .BinaryExpression(let s, let l, let r): return evaluateBinary(s, compute, l, r) case .FunctionCall(let f, let p): return evaluateFunction(f, compute(p)) default: return .EvaluationError("Couldn't evaluate expression") } } ?? .EvaluationError("Couldn't parse expression") } }
Mixing FP and OO class SpreadsheetDatasource : NSObject, NSTableViewDataSource, EditedRow
Mixing FP and OO var arr: [String] func tableView(aTableView: NSTableView,
objectValueForTableColumn: NSTableColumn, row: Int) -> AnyObject { return editedRow == row ? arr[row] : results[row] }
Mixing FP and OO func calculateExpressions() { let expressions: [Expression?]
= arr.map { if let tokens = parse(tokenize(), $0) { return parse(expression(), tokens) } return nil } results = evaluate(expressions) }
Conclusion FP is a massively powerful tool in your toolbox.
Use it together with OO, and build awesome stuff.
By Chris Eidhof, Florian Kugler and Wouter Swierstra
@chriseidhof