Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rob Napier: Lambda: There and Back AgainRob Napier

1fa9cb8c7997c8c4d3d251fb5e41f749?s=47 Realm
September 01, 2016

Rob Napier: Lambda: There and Back AgainRob Napier

Abstract/excerpt: I have been to Monad, to the Functor of Doom. I have seen the map, flattened and lensed. I have folded the infinite, lifted a Maybe, and I’d do it all over again. But from what I’ve seen, from Haskell to Church, we can rely on one truth, which is this: Swift is not a functional programming language. Pushing too hard to make it one fights Swift and breaks Cocoa.

But Swift has absorbed some fantastic lessons from the functional world, and while value types may not quite be the present, they are clearly the future. We’ll explore how decades of work in functional languages have influenced Swift, and how you can use those features best while staying true to Swift, playing nice with Cocoa, and embracing Protocol Oriented Programming.

Bio: Rob is co-author of iOS Programming Pushing the Limits. Before coming to Cocoa, he made his living sneaking into Chinese facilities in broad daylight. Later he became a Mac developer for Dell. It's not clear which was the stranger choice. He has a passion for the fiddly bits below the surface, like networking, performance, security, and text layout. He asks `but is it good Swift?` a lot.

Twitter: https://twitter.com/cocoaphony

1fa9cb8c7997c8c4d3d251fb5e41f749?s=128

Realm

September 01, 2016
Tweet

Transcript

  1. λ: THERE AND BACK AGAIN ROB NAPIER

  2. ≠ λ

  3. slice :: [a] -> Int -> Int -> [a] slice

    [] _ _ = [] slice xs i j = map snd . filter((>=i) . fst) $ zip [1..j] xs
  4. ≠ λ >>= <*> <$> %~ <+=

  5. FUNCTIONAL PROGRAMMING IS A WAY OF THINKING

  6. var persons: [Person] = [] for name in names {

    let person = Person(name: name) if person.isValid { persons.append(person) } }
  7. var persons: [Person] = [] for name in names {

    let person = Person(name: name) if person.isValid { persons.append(person) } }
  8. var persons: [Person] = [] for name in names {

    let person = Person(name: name) if person.isValid { persons.append(person) } }
  9. var persons: [Person] = [] for name in names {

    let person = Person(name: name) if person.isValid { persons.append(person) } }
  10. var persons: [Person] = [] for name in names {

    let person = Person(name: name) if person.isValid { persons.append(person) } }
  11. var possiblePersons: [Person] = [] for name in names {

    let person = Person(name: name) possiblePersons.append(person) } var persons: [Person] = [] for person in possiblePersons { if person.isValid { persons.append(person) } }
  12. let possiblePersons = names.map(Person.init) var possiblePersons: [Person] = [] for

    name in names { let person = Person(name: name) possiblePersons.append(person) }
  13. var persons: [Person] = [] for person in possiblePersons {

    if person.isValid { persons.append(person) } } let persons = possiblePersons.filter { $0.isValid }
  14. let possiblePersons = names.map(Person.init) let persons = possiblePersons.filter { $0.isValid

    } var persons: [Person] = [] for name in names { let person = Person(name: name) if person.isValid { persons.append(person) } }
  15. let persons = names .map(Person.init) .filter { $0.isValid }

  16. ▸ dropFirst ▸ dropLast ▸ forEach ▸ flatMap ▸ prefix

    ▸ split ▸ suffix ▸ first(where:) ▸ contains ▸ elementsEqual ▸ enumerated ▸ flatten ▸ joined ▸ max ▸ min ▸ reduce ▸ reversed ▸ sorted ▸ starts(with:) ▸ isEmpty ▸ count ▸ index(of:) ▸ index(where:) ▸ popFirst ▸ removeFirst ▸ … “FUNCTIONAL” TOOLS
  17. None
  18. let sum = foldr (+) 0 sum [1..10] HASKELL Create

    new function sum by combining
 existing functions foldr and +
  19. SWIFT Attach Sequence methods to MyStruct extension MyStruct<T>: Sequence {

    func makeIterator() -> AnyIterator<T> { return ... } }
  20. TYPE CONTEXT LIFTING A TYPE String ?

  21. let noValue = -1 let n = 0 if n

    != noValue { … } NO VALUE: MAGIC VALUE let n: Int? = 0 if let n = n { … } NO VALUE: CONTEXT
  22. func login(username: String, password: String, completion: (String?, Error?) -> Void)

    login(username: "rob", password: "s3cret") { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  23. func login(username: String, password: String, completion: (String?, Error?) -> Void)

    login(username: "rob", password: "s3cret") { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  24. func login(username: String, password: String, completion: (_ token: String?, Error?)

    -> Void) login(username: "rob", password: "s3cret") { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  25. struct Token { let string: String }

  26. func login(username: String, password: String, completion: (Token?, Error?) -> Void)

    login(username: "rob", password: "s3cret") { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  27. func login(username: String, password: String, completion: (Token?, Error?) -> Void)

    login(username: "rob", password: "s3cret") { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  28. “AND” TYPE (PRODUCT) struct Credential {
 var username: String var

    password: String }
  29. func login(credential: Credential, completion: (Token?, Error?) -> Void) let credential

    = Credential(username: "rob", password: "s3cret") login(credential: credential) { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  30. func login(credential: Credential, completion: (Token?, Error?) -> Void) let credential

    = Credential(username: "rob", password: "s3cret") login(credential: credential) { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  31. set nil set ⁇ ✅ nil ✅ ⁇ token error

    let credential = Credential(username: "rob", password: "s3cret") login(credential: credential) { (token, error) in if let token = token { // success } else if let error = error { // failure } }
  32. enum Result<Value> { case success(Value) case failure(Error) } “OR” TYPE

    (SUM)
  33. func login(credential: Credential, completion: (Result<Token>) -> Void) login(credential: credential) {

    result in switch result { case .success(let token): // success case .failure(let error): // failure } }
  34. → λ

  35. THE LESSONS ▸ Break apart complicated things into simpler things

    ▸ Look for generic patterns in the simple things ▸ Lift and compose simple things to make complex ones
  36. BREAK IT DOWN. BUILD IT UP. LAMBDA: THERE AND BACK

    AGAIN