Practical Declarative Programming (AltConf 2015)

Practical Declarative Programming (AltConf 2015)

A practical introduction to declarative programming and how it can be applied to the real world. The talk will cover functional programming concepts, which allows you to write clearer, declarative and testable code. Usually, functional programming is taught by abstract functional techniques. Which are often hard to relate and understand the real benefits. Instead this talk goes for a different approach by showing examples of unfunctional, imperative code that people write every day and how we can translate that to a functional declarative style.

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

June 12, 2015
Tweet

Transcript

  1. Practical Declarative Programming KyleFuller

  2. None
  3. None
  4. Imperative Programming

  5. Describe how to achive something

  6. Declarative Programming

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

  8. Why Declarative Programming?

  9. Readability

  10. Simplicity

  11. Constraint driven Less room for errors

  12. Why are we not doing declarative programming?

  13. How

  14. Domain Specific Languages (DSLs)

  15. Constraints

  16. Regular expressions

  17. \d\d / \d\d / \d\d\d\d 12 / 06 / 2015

  18. SQL Structured Query Language

  19. SELECT * FROM comments WHERE author == 'Kyle'

  20. NSPredicate

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

  22. Functional Programming

  23. What makes up functional programming?

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

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

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

  27. What is not functional function?

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

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

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

    1 }
  31. High Order Functions

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

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

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

  35. State of callables in Objective-C

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

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

  38. void message(NSString *value) { }

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

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

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

  43. Callables in Swift

  44. (String) -> ()

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

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

  47. func message(value:String) { }

  48. message("AltConf")

  49. Interchangeability

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

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

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

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

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

  55. How many people are in each group?

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

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

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

  59. transform (item) -> (T)

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

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

  62. transform (item) -> (T)

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

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

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

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

  67. sorted

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

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

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

    = [2, 3]
  71. 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
  72. Operators are closures

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

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

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

  76. 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"]
  77. reduce

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

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

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

  81. reduce(groups, [], +)

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

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

  84. 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"]]
  85. let input = "Kyle,Katie\nAndré,Maxine,Ash" let groups = map(input.componentsSeparatedByString("\n")) { line

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

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

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

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

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

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

    "Maxine", "Ash"]]
  92. Why are map and reduce better?

  93. Declarative

  94. Immutability

  95. Don’t iterate over arrays

  96. Don’t iterate over arrays 4 Use map

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

  98. Write declaratively Not imperatively

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

    build simpler generic declaritive languages 4 We’ve seen how Functional Programming can be used to build declarative code 4 We’ve seen how declarative code helps simplicity, testability and on boarding new developers
  100. fuller.li/talks KyleFuller kyle@fuller.li