Swift Functional Programming

6ed02dec32058508c6feb43b2fbc94f7?s=47 Secret Lab
February 02, 2016

Swift Functional Programming

Overview of the basics of Functional Programming using the Swift programming language. Presented at the Functional Programming Miniconf at Linux.conf.au 2016, in Geelong.

6ed02dec32058508c6feb43b2fbc94f7?s=128

Secret Lab

February 02, 2016
Tweet

Transcript

  1. Swift Functional Programming @parisba

  2. None
  3. None
  4. None
  5. Agenda • What is Swift • Why bother? • Installing

    Swift • Playgrounds/REPL • Functional Programming Fundamentals • Swift Functional Programming
  6. This is mostly a “how Swift does it” talk

  7. A quick overview. Not all-inclusive.

  8. Swift?! • Similar to Rust, Perl 6, and a bunch

    of other languages… • Another trendy, hip, cool, modern programming language… • Actually pretty good…
  9. Why does Swift matter?

  10. Swift is open source. swift.org

  11. Swift is easy to teach.

  12. iOS.

  13. http://blog.appannie.com/app-annie-2015-retrospective/ Annual App Downloads, 2013 - 2015

  14. http://blog.appannie.com/app-annie-2015-retrospective/ Annual App Revenue, 2013 - 2015

  15. None
  16. let = ["","",""] for in { print() }

  17. Swift is not really a functional language

  18. Nothing like a pure functional language.

  19. Ideals of functional programming are important

  20. Installing Swift

  21. Available on Linux and OS X (OS X installation: just

    download Xcode)
  22. Binaries available for Ubuntu

  23. $ sudo apt-get install clang libicu-dev Download a binary from

    https://swift.org/download/#linux; extract it $ tar xzf swift-<VERSION>-<PLATFORM>.tar.gz $ export PATH=/path/to/usr/bin:"${PATH}" This creates a usr/ directory; add it to your path: Swift is now installed! Download the pre-requisites:
  24. Useful Swifty Things

  25. Playgrounds

  26. $ swift Welcome to Apple Swift version 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81).

    Type :help for assistance. 1> let text = "Don t worry if you are not computer" text: String = "Don t worry if you are not computer" 2> text.uppercaseString $R0: String = "DON T WORRY IF YOU ARE NOT COMPUTER" 3>
  27. What does functional programming mean?

  28. Functions

  29. First-class functions

  30. Higher-order functions

  31. Pure functions

  32. Pure functions have no side effects.

  33. No I/O, no changing outside state.

  34. Why does functional programming matter?

  35. © GDC CC-BY 2.0

  36. –John Carmack “No matter what language you work in, programming

    in a functional style provides benefits. You should do it whenever it is convenient, and you should think hard about the decision when it isn't convenient.”
  37. yeah ok but WHY

  38. “Pure functions have a lot of nice properties.”

  39. • Thread safety • Reusability • Testability • Understandability •

    Maintainability
  40. Important Language Support

  41. A really nice type system.

  42. First-class functions. See also: lambda calculus, Haskell, OCaml, Scala, and

    so on.
  43. func add(num1: Int, _ num2 : Int) -> Int {

    return num1 + num2 }
  44. func add(num1: Int, _ num2 : Int) -> Int {

    return num1 + num2 } var addNumbers : (Int,Int) -> Int
  45. func add(num1: Int, _ num2 : Int) -> Int {

    return num1 + num2 } var addNumbers : (Int,Int) -> Int addNumbers = add
  46. func add(num1: Int, _ num2 : Int) -> Int {

    return num1 + num2 } var addNumbers : (Int,Int) -> Int addNumbers = add addNumbers(1,2)
  47. Closures

  48. Inline first-class functions

  49. var add = { (num1 : Int, num2 : Int)

    -> Int in return num1 + num2 }
  50. Swift will infer as much type info as it can

  51. var add = { (num1 : Int, num2 : Int)

    -> Int in return num1 + num2 }
  52. var add = { (num1 : Int, num2 : Int)

    -> Int in return num1 + num2 }
  53. var add = { (num1 : Int, num2 : Int)

    -> Int in return num1 + num2 }
  54. var add : (Int,Int) -> Int add = { $0

    + $1 }
  55. var add : (Int,Int) -> Int add = (+)

  56. Value capturing

  57. typealias Adder = (Int) -> Int

  58. typealias Adder = (Int) -> Int func makeAdder(number: Int) ->

    Adder { return { $0 + number } }
  59. typealias Adder = (Int) -> Int func makeAdder(number: Int) ->

    Adder { return { $0 + number } } let addTwo = makeAdder(2)
  60. typealias Adder = (Int) -> Int func makeAdder(number: Int) ->

    Adder { return { $0 + number } } let addTwo = makeAdder(2) addTwo(5) // 7
  61. First-class functions means we get higher-order functions!

  62. typealias TwoIntegerFunction = (Int,Int) -> Int

  63. typealias TwoIntegerFunction = (Int,Int) -> Int func applyOperationToNumbers(num1 : Int,

    _ num2 : Int, operation: TwoIntegerFunction) -> Int { return operation(num1, num2) }
  64. typealias TwoIntegerFunction = (Int,Int) -> Int func applyOperationToNumbers(num1 : Int,

    _ num2 : Int, operation: TwoIntegerFunction) -> Int { return operation(num1, num2) } let add : TwoIntegerFunction = { $0 + $1 }
  65. typealias TwoIntegerFunction = (Int,Int) -> Int func applyOperationToNumbers(num1 : Int,

    _ num2 : Int, operation: TwoIntegerFunction) -> Int { return operation(num1, num2) } let add : TwoIntegerFunction = { $0 + $1 } applyOperationToNumbers(2, 3, operation: add)
  66. typealias TwoIntegerFunction = (Int,Int) -> Int func applyOperationToNumbers(num1 : Int,

    _ num2 : Int, operation: TwoIntegerFunction) -> Int { return operation(num1, num2) } let add : TwoIntegerFunction = { $0 + $1 } applyOperationToNumbers(2, 3, operation: add) applyOperationToNumbers(2, 3, operation: +)
  67. Optionals

  68. In Swift, variables are never allowed to be nil, unless

    they’re Optionals.
  69. var text = "As you might know, I am a

    full time Internet" text.uppercaseString // "AS YOU MIGHT KNOW, I AM A FULL TIME INTERNET"
  70. let textFromDisk = loadTextFromDisk() textFromDisk.uppercaseString // Error!!

  71. Very similar to Haskell’s Maybe

  72. let textFromDisk = loadTextFromDisk() textFromDisk?.uppercaseString // "EVERYTHING HAPPENS SO MUCH"

  73. Some Contrived Examples using Swift

  74. func incrementArray(theArray: [Int]) -> [Int] { var result: [Int] =

    [] for item in theArray { result.append(item+1) } return result }
  75. func doubleArray(theArray: [Int]) -> [Int] { var result: [Int] =

    [] for item in theArray { result.append(item*2) } return result }
  76. typealias TransformFunction = Int -> Int func manipulateArray(theArray: [Int], transform:

    TransformFunction) -> [Int] { var result: [Int] = [] for item in theArray { result.append(transform(item)) } return result }
  77. func doubleArray(xs: [Int]) -> [Int] { return manipulateArray(xs, transform:{ $0*2

    }) }
  78. Limitations…

  79. [ ] , , , Int Int Int Int [

    ] , , , Int Int Int Int
  80. [ ] , , , Int Int Int Int [

    ] , , , ? Bool Bool Bool Bool
  81. Writing duplicate versions sucks

  82. Generics!

  83. func manipulateArray(theArray: [Int], transform: TransformFunction) -> [Int] { var result:

    [Int] = [] for item in theArray { result.append(transform(item)) } return result }
  84. func map<T>(xs: [Int], transform: Int->T) -> [T] { var result:

    [T] = [] for x in xs { result.append(transform(x)) } return result }
  85. func map<T>(xs: [Int], transform: Int->T) -> [T] { var result:

    [T] = [] for x in xs { result.append(transform(x)) } return result }
  86. But we can take it further…

  87. func map<Element, T>(xs: [Element], transform: Element->T) -> [T] { var

    result: [T] = [] for x in xs { result.append(transform(x)) } return result }
  88. let doubledArray = map([1,2,3,4], transform: { $0 * 2} )

  89. extension Array { func map<T>(transform: (Element) -> T) -> [T]

    { var result: [T] = [] for x in self { result.append(transform(x)) } return result } }
  90. [1,2,3,4].map({ $0 * 2 })

  91. Map actually comes with Swift Hopefully you were expecting me

    to say that… … the point is, there’s no secrets to Map!
  92. Composing functions

  93. 10 11 +1 ×2

  94. 5 10 11 +1 ×2

  95. 5 10 11 +1 ×2

  96. 5 10 11 +1 ×2

  97. 5 10 11 +1 ×2

  98. ×2 +1

  99. 11 ×2 +1

  100. 5 11 ×2 +1

  101. 5 11 ×2 +1

  102. // Compose a function from two functions func compose<T>(funcA: T->T,

    _ funcB: T->T) -> T->T { // Return a new function that calls them both return { funcB(funcA($0)) } }
  103. // Compose a function from two functions func compose<T>(funcA: T->T,

    _ funcB: T->T) -> T->T { // Return a new function that calls them both return { funcB(funcA($0)) } } // Two dumb lil functions let double = { $0 * 2 } let addOne = { $0 + 1 }
  104. // Compose a function from two functions func compose<T>(funcA: T->T,

    _ funcB: T->T) -> T->T { // Return a new function that calls them both return { funcB(funcA($0)) } } // Two dumb lil functions let double = { $0 * 2 } let addOne = { $0 + 1 } // Compose 'em! let doubleAndAddOne = compose(double, addOne)
  105. // Compose a function from two functions func compose<T>(funcA: T->T,

    _ funcB: T->T) -> T->T { // Return a new function that calls them both return { funcB(funcA($0)) } } // Two dumb lil functions let double = { $0 * 2 } let addOne = { $0 + 1 } // Compose 'em! let doubleAndAddOne = compose(double, addOne) doubleAndAddOne(5)
  106. Limitations!

  107. func compose<T>(funcA: T->T, _ funcB: T->T) -> T->T These have

    to be the same type, for no good reason!
  108. Is Even? Flip Boolean Bool Int Bool Bool

  109. No Is Even? Flip Boolean

  110. 4 No Is Even? Flip Boolean

  111. 4 No Is Even? Flip Boolean

  112. func compose<T>(funcA: T->T, _ funcB: T->T) -> T->T { return

    { funcB(funcA($0)) } }
  113. func compose<T,U,V>(funcA: T->U, _ funcB: U->V) -> T->V { return

    { funcB(funcA($0)) } }
  114. func compose<T,U,V>(funcA: T->U, _ funcB: U->V) -> T->V { return

    { funcB(funcA($0)) } } let isEven = { $0 % 2 == 0 } // Int -> Bool let flipBool = { !$0 } // Bool -> Bool let isNotEven = compose(isEven, flipBool) // Int -> Bool isNotEven(4) // false
  115. Third-party Stuff

  116. Swiftz https://github.com/typelift/swiftz

  117. Better types and tools for FP

  118. import struct Swiftz.List // Cycles a finite list of numbers

    into an infinite list. let finite : List<UInt> = [1, 2, 3, 4, 5] let infiniteCycle = finite.cycle() // Lists also support the standard map, filter, and reduce operators. let l : List<Int> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] let twoToEleven = l.map(+1) // [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] let even = l.filter((==0) • (%2)) // [2, 4, 6, 8, 10] let sum = l.reduce(curry(+), initial: 0) // 55 // Plus a few more. let partialSums = l.scanl(curry(+), initial: 0) // [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55] let firstHalf = l.take(5) // [1, 2, 3, 4, 5] let lastHalf = l.drop(5) // [6, 7, 8, 9, 10]
  119. Promissum https://github.com/tomlokhorst/Promissum

  120. Dollar.swift dollarswift.org

  121. Result https://github.com/antitypical/Result

  122. Learning more • Learn You a Haskell for Great Good!

    • Pearls of Functional Algorithm Design • Programming in Haskell (Hutton) • Apple’s Swift Book(s) • IBM Swift Resources: https://developer.ibm.com/swift/
  123. Thank you @parisba / http://www.secretlab.com.au