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 programming for UI
Search
Teddy Ku
November 14, 2018
Programming
1
2.7k
Functional programming for UI
Turn the pyramid of doom into a line of happiness
Teddy Ku
November 14, 2018
Tweet
Share
More Decks by Teddy Ku
See All by Teddy Ku
Concurrency in Swift
tkuichooseyou
2
2.5k
ReactiveSwift
tkuichooseyou
0
83
Other Decks in Programming
See All in Programming
なんとなくわかった気になるブロックテーマ入門/contents.nagoya 2025 6.28
chiilog
1
210
GoのGenericsによるslice操作との付き合い方
syumai
3
690
GitHub Copilot and GitHub Codespaces Hands-on
ymd65536
1
120
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
540
Cline指示通りに動かない? AI小説エージェントで学ぶ指示書の書き方と自動アップデートの仕組み
kamomeashizawa
1
570
A2A プロトコルを試してみる
azukiazusa1
2
1.1k
Team topologies and the microservice architecture: a synergistic relationship
cer
PRO
0
1k
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
150
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
440
プロダクト志向ってなんなんだろうね
righttouch
PRO
0
160
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
190
エンジニア向け採用ピッチ資料
inusan
0
160
Featured
See All Featured
How to train your dragon (web standard)
notwaldorf
93
6.1k
A Tale of Four Properties
chriscoyier
160
23k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Stop Working from a Prison Cell
hatefulcrawdad
270
20k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
20k
Navigating Team Friction
lara
187
15k
Rails Girls Zürich Keynote
gr2m
94
14k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.8k
Writing Fast Ruby
sferik
628
61k
Optimizing for Happiness
mojombo
379
70k
The World Runs on Bad Software
bkeepers
PRO
69
11k
Transcript
Teddy Ku 'VODUJPOBMQSPHSBNNJOHGPS6*
2 Copyright © Merpay, Inc. All Rights Reserved. 5FEEZ,V !ULVJDIPPTFZPV
!ULVJDIPPTFZPV 4UBUVT
3 Copyright © Merpay, Inc. All Rights Reserved. 'FBUVSF 0OCPBSEJOHUVUPSJBMT
4 Copyright © Merpay, Inc. All Rights Reserved. 'FBUVSF 0OCPBSEJOHUVUPSJBMT
5 0OCPBSEJOHUVUPSJBMT Copyright © Merpay, Inc. All Rights Reserved.
6 Copyright © Merpay, Inc. All Rights Reserved. class BalloonView:
UIView { var onTapped: (() -> Void)? var contentView: UIView func show() { /* ... */ } func dismiss() { /* ... */ } /* ... */ }
7 Copyright © Merpay, Inc. All Rights Reserved. class ViewController:
UIViewController { func showTutorialFlow() { let tutorialOne = tutorialOneBalloonView() let tutorialTwo = tutorialTwoBalloonView() let tutorialThree = tutorialThreeBalloonView() tutorialOne.onTapped = { [weak tutorialOne] in tutorialOne?.dismiss() tutorialTwo.show() } tutorialTwo.onTapped = { [weak tutorialTwo] in tutorialTwo?.dismiss() tutorialThree.show() } tutorialThree.onTapped = { [weak self, weak tutorialThree] in tutorialThree?.dismiss() self?.hideGrayOverlay { } } showGrayOverlay { tutorialOne.show() } }
8 Copyright © Merpay, Inc. All Rights Reserved. class ViewController:
UIViewController { func showTutorialFlow() { let tutorialOne = tutorialOneBalloonView() let tutorialTwo = tutorialTwoBalloonView() let tutorialThree = tutorialThreeBalloonView() %PO`UXBOUUPJOTUBOUJBUFFWFSZUIJOHVQGSPOU 0OMZOFFEPOFWJFXBUBUJNF
9 Copyright © Merpay, Inc. All Rights Reserved. 3FXSJUFPOFWJFXBUBUJNF
class ViewController: UIViewController { func showTutorialFlow() { let tutorialOne =
tutorialOneBalloonView() tutorialOne.onTapped = { [weak tutorialOne] in tutorialOne?.dismiss() let tutorialTwo = tutorialTwoBalloonView() tutorialTwo.onTapped = { [weak tutorialTwo] in tutorialTwo?.dismiss() let tutorialThree = tutorialThreeBalloonView() tutorialThree.onTapped = { [weak self, weak tutorialThree] in tutorialThree?.dismiss() self?.hideGrayOverlay { } } tutorialThree.show() } tutorialTwo.show() } showGrayOverlay { tutorialOne.show() } } 10 Copyright © Merpay, Inc. All Rights Reserved. Pyramid of doom
11 Copyright © Merpay, Inc. All Rights Reserved. /FTUFEDMPTVSFT )PXUPEFBMXJUIUIFN
12 Copyright © Merpay, Inc. All Rights Reserved. 'VODUJPOTJOGVODUJPOT -FU`TVTFGVODUJPOT
'VODUJPOBM1SPHSBNNJOH
13 Copyright © Merpay, Inc. All Rights Reserved. 5IJOLUPQEPXO 8IBUXPVMEUIFJEFBMTPMVUJPOMPPLMJLF
14 Copyright © Merpay, Inc. All Rights Reserved. func showTutorialFlow()
{ let tutorialBalloon = tutorialOneBalloonView() let transitions = tutorialBalloon.onTapped({ inputBalloonView in inputBalloonView?.dismiss() return tutorialTwoBalloonView() }) >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialThreeBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFourBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFiveBalloonView() } >>> { [weak self] inputBalloonView in inputBalloonView?.dismiss() self?.hideGrayOverlay { } return nil } tutorialBalloon.show(onTapped: transitions) } $PNQPTBCMFUSBOTJUJPOGVODUJPOT
15 Copyright © Merpay, Inc. All Rights Reserved. )PXXPVMEXFJNQMFNFOUUIJT
16 Copyright © Merpay, Inc. All Rights Reserved. typealias BalloonTransition
= (BalloonView?) -> BalloonView? // associativity: right infix operator >>>: FunctionArrowPrecedence func >>> ( transitionOne: @escaping BalloonTransition, transitionTwo: @escaping BalloonTransition) -> BalloonTransition { return { balloonView in balloonView?._nextTransition = transitionTwo return transitionOne(balloonView) } } 1 >>> (2 >>> (3 >>> (4 >>> 5)))
17 Copyright © Merpay, Inc. All Rights Reserved. func >>>
( transitionOne: @escaping BalloonTransition, transitionTwo: @escaping BalloonTransition) -> BalloonTransition { return { balloonView in balloonView?._nextTransition = transitionTwo return transitionOne(balloonView) } } 1 >>> (2 >>> (3 >>> (4 >>> 5))) func showTutorialFlow() { let tutorialBalloon = tutorialOneBalloonView() let transitions = tutorialBalloon.onTapped({ inputBalloonView in inputBalloonView?.dismiss() return tutorialTwoBalloonView() }) >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialThreeBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFourBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFiveBalloonView() } >>> { [weak self] inputBalloonView in inputBalloonView?.dismiss() self?.hideGrayOverlay { } return nil } tutorialBalloon.show(onTapped: transitions) }
18 Copyright © Merpay, Inc. All Rights Reserved. func showTutorialFlow()
{ let tutorialBalloon = tutorialOneBalloonView() let transitions = tutorialBalloon.onTapped({ inputBalloonView in inputBalloonView?.dismiss() return tutorialTwoBalloonView() }) >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialThreeBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFourBalloonView() } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFiveBalloonView() } >>> { [weak self] inputBalloonView in inputBalloonView?.dismiss() self?.hideGrayOverlay { } return nil } tutorialBalloon.show(onTapped: transitions) } func >>> ( transitionOne: @escaping BalloonTransition, transitionTwo: @escaping BalloonTransition) -> BalloonTransition { return { balloonView in balloonView?._nextTransition = transitionTwo return transitionOne(balloonView) } } } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFiveBalloonView() } >>> { [weak self] inputBalloonView in inputBalloonView?.dismiss() self?.hideGrayOverlay { } return nil } -BTUUXPDMPTVSFT
Copyright © Merpay, Inc. All Rights Reserved. { balloon4 in
balloon4.nextTransition = { [weak self] balloon5 in balloon5?.dismiss() self?.hideGrayOverlay { } return nil } balloon4?.dismiss() return tutorialFiveBalloonView() } } >>> { inputBalloonView in inputBalloonView?.dismiss() return tutorialFiveBalloonView() } >>> { [weak self] inputBalloonView in inputBalloonView?.dismiss() self?.hideGrayOverlay { } return nil } FYFDVUFXIFOCBMMPPOJTUBQQFE FYFDVUFXIFO CBMMPPOJTUBQQFE 8IBUEPFTSFUVSOTBDMPTVSF OPUBDUVBMDPEF
Copyright © Merpay, Inc. All Rights Reserved. balloon3.nextTransition = {
balloon4 in balloon4.nextTransition = { [weak self] balloon5 in balloon5?.dismiss() self?.hideGrayOverlay { } return nil } balloon4?.dismiss() return tutorialFiveBalloonView() } balloon3?.dismiss() return tutorialFourBalloonView() GVODUJPOXJMMTFUUIFDMPTVSFUP UIFQSFWJPVT#BMMPPO7JFX 8IBUEPFT OPUBDUVBMDPEF
Copyright © Merpay, Inc. All Rights Reserved. balloon2.nextTransition = {
balloon3 in balloon3.nextTransition = { balloon4 in balloon4.nextTransition = { [weak self] balloon5 in balloon5?.dismiss() self?.hideGrayOverlay { } return nil } balloon4?.dismiss() return tutorialFiveBalloonView() } balloon3?.dismiss() return tutorialFourBalloonView() } balloon2?.dismiss() return tutorialThreeBalloonView() 8IBUEPFT OPUBDUVBMDPEF
Copyright © Merpay, Inc. All Rights Reserved. tutorialBalloon.show(onTapped: { balloon1
in balloon1.nextTransition = { balloon2 in balloon2.nextTransition = { balloon3 in balloon3.nextTransition = { balloon4 in balloon4.nextTransition = { [weak self] balloon5 in balloon5?.dismiss() self?.hideGrayOverlay { } return nil } balloon4?.dismiss() return tutorialFiveBalloonView() } balloon3?.dismiss() return tutorialFourBalloonView() } balloon2?.dismiss() return tutorialThreeBalloonView() } balloon1?.dismiss() return tutorialTwoBalloonView() }) 8IBUEPFT OPUBDUVBMDPEF
Copyright © Merpay, Inc. All Rights Reserved. tutorialBalloon.show(onTapped: { balloon1
in balloon1.nextTransition = { balloon2 in balloon2.nextTransition = { balloon3 in balloon3.nextTransition = { balloon4 in balloon4.nextTransition = { [weak self] balloon5 in balloon5?.dismiss() self?.hideGrayOverlay { } return nil } balloon4?.dismiss() return tutorialFiveBalloonView() } balloon3?.dismiss() return tutorialFourBalloonView() } balloon2?.dismiss() return tutorialThreeBalloonView() } balloon1?.dismiss() return tutorialTwoBalloonView() })
24 Copyright © Merpay, Inc. All Rights Reserved. .JTTJPOBDDPNQMJTIFE 3FBEBCMFDPEF
0OMZPOF#BMMPPO7JFXJONFNPSZ
25 Copyright © Merpay, Inc. All Rights Reserved. $VSSZJOH func
add(x: Int) -> ((Int) -> Int) { return { y in return x + y } } // Removed in Swift 3 // https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md func foo(x: Int)(y: Int)
26 Copyright © Merpay, Inc. All Rights Reserved. typealias Filter
= (CIImage) -> CIImage let myFilter = blur(blurRadius) >>> colorOverlay(overlayColor) let result = myFilter(image) *OTQJSBUJPO'VODUJPOBM4XJGU PCKDJP
27 Copyright © Merpay, Inc. All Rights Reserved. 4XJGU0CKFDUJWF$
28 Copyright © Merpay, Inc. All Rights Reserved. 5IBOLZPV HJUIVCDPNNFSDBSJ#BMMPPO7JFX