Practical Functional Programming (dotSwift 2015)

D200a17dd269fd4001bacb11662dab4b?s=47 Kyle Fuller
February 06, 2015

Practical Functional Programming (dotSwift 2015)

A practical introduction to functional programming in Swift and how it can be applied to the real world. Going over what being functional means and how it allows you to write clearer, declarative and testable code.

Usually, functional programming is taught by abstract functional techniques. Instead this talk goes for a different approach showing examples of unfunctional, imperative code people may have written in the past and how that can be improved with a functional style.

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

February 06, 2015
Tweet

Transcript

  1. Practical Functional Programming @kylefuller

  2. Imperative

  3. Declarative

  4. Describe what to do Not how to do it.

  5. What makes up functional programming?

  6. What makes up functional programming? 4 first class functions 4

    immutable data 4 reducing 4 pipelining 4 recursing 4 currying 4 monads
  7. What makes up functional programming? 4 first class functions 4

    immutable data 4 reducing 4 pipelining 4 recursing 4 currying 4 monads
  8. Side-effects

  9. What is not functional function?

  10. Un-functional Function var value = 0 func increment() { value

    += 1 }
  11. Un-functional Function func increment() { let center = NSNotificationCenter.defaultCenter() let

    value = center.valueForKey("key") as? Int ?? 0 center.setValue(value + 1, forKey: "key") }
  12. Functional Function func increment(value:Int) -> Int { return value +

    1 }
  13. High Order Functions

  14. High Order Functions 4 Functions that take other functions as

    arguments 4 Functions that returns a functions
  15. Everything is a closure

  16. State of callables in Objective-C

  17. @implementation Object - (void)message:(NSString *)value { } @end

  18. @implementation Object - (void)message:(NSString *)value { } @end [object message:@“Hello”];

  19. void message(NSString *value) { }

  20. void message(NSString *value) { } message(@“Hello”);

  21. void (^message)(NSString *value) = ^void(NSString *value) { };

  22. None
  23. void (^message)(NSString *value) = ^void(NSString *value) { }; message(@“Hello”);

  24. Callables in Swift

  25. (String) -> ()

  26. let message:(String -> ())

  27. let message:(String -> ()) = { value in }

  28. func message(value:String) { }

  29. message("dotSwift")

  30. Interchangeability

  31. func message1(value:String) { println(“Hello \(value)”) }

  32. func message1(value:String) { println(“Hello \(value)”) } var message2:(String -> ())

    = { value in println(“Hi \(value)”) }
  33. func message1(value:String) { println(“Hello \(value)”) } var message2:(String -> Void)

    = { value in println(“Hi \(value)”) } message2 = message1 message2(“dotSwift”) // Hello dotSwift
  34. Functional programming by Example

  35. let groups = [ ["Kyle", "Maxine"], ["André", "Katie", "Ash"] ]

  36. How many people are in each group?

  37. How many people are in each group? let groups =

    [["Kyle", "Maxine"], ["André", "Katie", "Ash"]] var count = [Int]() for group in groups { let people = countElements(group) count.append(people) } count // [2, 3]
  38. map

  39. map (source, transform) -> ([T])

  40. transform (item) -> (T)

  41. How many people are in each group? let groups =

    [["Kyle", "Maxine"], ["André", "Katie", "Ash"]] map(groups) { countElements($0) } // [2, 3]
  42. countElements (sequence) -> (Int)

  43. transform (item) -> (T)

  44. (item) -> (T) (sequence) -> (Int)

  45. How many people are in each group? let groups =

    [["Kyle", "Maxine"], ["André", "Katie", "Ash"]] map(groups, countElements) // [2, 3]
  46. Order the numbers of people in each group

  47. [2, 3] -> [3, 2]

  48. sorted

  49. sorted (sequence, isOrderedBefore) -> (sequence)

  50. isOrderedBefore (lhs, rhs) -> (Bool)

  51. Order the numbers of people in each group let count

    = [2, 3]
  52. Order the numbers of people in each group let count

    = [2, 3] sorted(count) { (lhs, rhs) in lhs > rhs } // largest group is [3, 2].first
  53. Operators are closures

  54. > (lhs, rhs) -> (Bool)

  55. let count = [2, 3] sorted(count, >) // largest group

    is [3, 2].first
  56. Building an array of all people

  57. Building an array of all people let groups = [["Kyle",

    "Maxine"], ["André", "Katie", "Ash"]] var people = [String]() for group in groups { people += group } // ["Kyle", "Maxine", "André", "Katie", "Ash"]
  58. reduce

  59. reduce (sequence, initial(U), combine) -> (U)

  60. combine (U, value) -> (U)

  61. + (U, U) -> (U)

  62. reduce(groups, [], +)

  63. Building an array of all people let groups = [["Kyle",

    "Maxine"], ["André", "Katie", "Ash"]] reduce(groups, [], +) // ["Kyle", "Maxine", "André", "Katie", "Ash"]
  64. let input = "Kyle,Maxine\nAndré,Katie,Ash"

  65. let input = "Kyle,Maxine\nAndré,Katie,Ash" var groups = [[String]]() for line

    in input.componentsSeparatedByString("\n") { let group = line.componentsSeparatedByString(",") groups.append(group) } groups // [["Kyle", "Maxine"], ["André", "Katie", "Ash"]]
  66. let input = "Kyle,Maxine\nAndré,Katie,Ash" let groups = map(input.componentsSeparatedByString("\n")) { line

    in line.componentsSeparatedByString(",") } groups // [["Kyle", "Maxine"], ["André", "Katie", "Ash"]]
  67. let input = "Kyle,Maxine\nAndré,Katie,Ash" func commaSeparator(input:String) -> [String] { return

    input.componentsSeparatedByString(",") } map(input.componentsSeparatedByString("\n"), commaSeparator) // [["Kyle", "Maxine"], ["André", "Katie", "Ash"]]
  68. High Order Functions 4 Functions that returns a functions

  69. func separateBy(separator:String) -> ((String) -> [String]) { func inner(source:String) ->

    [String] { return source.componentsSeparatedByString(separator) } return inner }
  70. func separateBy(separator:String) -> ((String) -> [String]) { func inner(source:String) ->

    [String] { return source.componentsSeparatedByString(separator) } return inner } let lineSeparator = separateBy("\n") let commaSeparator = separateBy(",")
  71. func separateBy(separator:String)(source:String) -> [String] { return source.componentsSeparatedByString(separator) } let lineSeparator

    = separateBy("\n") let commaSeparator = separateBy(",")
  72. let input = "Kyle,Maxine\nAndré,Katie,Ash" map(lineSeparator(input), commaSeparator) // [["Kyle", "Maxine"], ["André",

    "Katie", "Ash"]]
  73. Why are map and reduce better?

  74. Declarative

  75. Immutability

  76. Don’t iterate over arrays

  77. Don’t iterate over arrays 4 Use map

  78. Don’t iterate over arrays 4 Use map 4 Use reduce

  79. Write declaratively Not imperatively