Pro Yearly is on sale from $80 to $50! »

Practical Declarative Programming (360 iDev 2015)

Practical Declarative Programming (360 iDev 2015)

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

August 19, 2015
Tweet

Transcript

  1. Practical Declarative Programming KyleFuller

  2. Imperative Programming

  3. Describe how to achieve something

  4. Declarative Programming

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

  6. Why Declarative Programming?

  7. Implementation Details

  8. Simplicity

  9. Constraint driven Less room for errors

  10. How can we do declarative programming?

  11. Domain Specific Languages (DSLs)

  12. Constraints

  13. Regular expressions

  14. Date Regex Pattern \d\d / \d\d / \d\d\d\d

  15. Date Regex Pattern Match 19 / 08 / 2015

  16. SQL Structured Query Language

  17. SQL Query SELECT * FROM comments WHERE author == 'Kyle'

  18. NSPredicate

  19. NSPredicate(format: "name == 'Kyle'")

  20. None
  21. Retrieve People 4 name is Kyle 4 ordered by name

  22. Traditionally let fetchRequest = NSFetchRequest(entityName: "Person") fetchRequest.predicate = NSPredicate(format: "name

    == %@", "Kyle") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)] var error:NSErrorPointer? var objects = managedObjectContext.executeFetchRequest(fetchRequest, error: error) if let objects = objects { ... }
  23. With QueryKit Person.queryset(context) .orderBy(Person.name.ascending) .filter(Person.name == "Kyle")

  24. Functional Programming

  25. What makes up functional programming?

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

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

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

  29. What is not functional function?

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

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

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

    1 }
  33. High Order Functions

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

    arguments
  35. High Order Functions 4 Functions that take other functions as

    arguments 4 Functions that returns a functions
  36. Everything is a function

  37. State of callables in Objective-C

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

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

  40. void message(NSString *value) { } In Objective-C, we can also

    declare functions. This may resemble the declaration method slightly from our previous examples.
  41. void message(NSString *value) { } message(@“Hello”);

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

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

  45. Callables in Swift

  46. (String) -> ()

  47. let message:(String -> ()) We can define a constant that

    is callable using this syntax. It's very similar to above, we have taken the definition from the previous slide and prefixed the variable name.
  48. let message:(String -> ()) = { value in }

  49. func message(value:String) { }

  50. message("AltConf")

  51. Interchangeability

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

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

    = { value in println(“Hi \(value)”) }
  54. (String) -> ()

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

    = { value in println(“Hi \(value)”) } message2 = message1 message2("360 iDev") // Hello 360 iDev
  56. Functional programming by Example

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

  58. How many people are in each group?

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

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

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

  62. transform (item) -> (T)

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

    [["Kyle", "Katie"], ["André", "Maxine", "Ash"]] groups.map { $0.count } // [2, 3]
  64. How many people are in each group? let groups =

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

  66. transform (item) -> (T)

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

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

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

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

  71. sort

  72. sort (sequence, isOrderedBefore) -> (sequence)

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

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

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

    = [2, 3] count.sort { (lhs, rhs) in lhs > rhs } // largest group is [3, 2].first
  76. Operators are functions

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

  78. let count = [2, 3] count.sort(>) // largest group is

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

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

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

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

  83. combine (U, T) -> (U)

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

  85. groups.reduce([], combine: +)

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

    "Katie"], ["André", "Maxine", "Ash"]] groups.reduce([], combine: +) // ["Kyle", "Katie", "André", "Maxine", "Ash"]
  87. Parsing Serialised Groups let input = "Kyle,Katie\nAndré,Maxine,Ash"

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

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

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

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

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

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

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

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

    "Ash"]]
  96. Why are map and reduce better?

  97. Declarative

  98. Immutability

  99. Performance

  100. $ ./performance.swift Total time taken for 1 million iterations. Declarative:

    10.7468339800835s Imperative: 12.156073987484s
  101. Don’t iterate over arrays

  102. Don’t iterate over arrays 4 Use map

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

  104. Write declaratively Not imperatively

  105. Conclusion 4 DSLs can be used to reduce bugs and

    build simpler generic declarative languages 4 We’ve seen how Functional Programming can be used to build declarative code 4 We’ve seen how declarative code helps simplicity, test-ability and on boarding new developers
  106. fuller.li/360idev KyleFuller kyle@fuller.li