Abizer Nasir
June 10, 2015
480

My talk from AltConf 2015

June 10, 2015

Transcript

@abizern | abizern.org Swift Contractor - Shutl

6. summer :: Int -> Int -> Int summer a b

= a + b λ> :t summer summer :: Int -> Int -> Int
7. --summer :: Int -> Int -> Int summer a b

= a + b λ> :t summer summer :: Num a => a -> a -> a
8. λ> :i + class Num a where (+) :: a

-> a -> a ... -- Defined in ‘GHC.Num’ infixl 6 +

10. ▸ Values don’t change under you. ▸ Easier to maintain

the code. ▸ More likely to be thread safe.
11. ▸ Prefer let to var ▸ Prefer structs over classes

where possible. ▸ Avoid mutating structs.

15. HIGHER ORDER FUNCTIONS let list = [1, 2, 3, 4]

let squares = list.map{\$0 * \$0} let evens = list.filter{\$0 % 2 == 0} let sum = list.reduce(0, combine: +)
16. REDUCE IS OFTEN ENOUGH let squares2 = list.reduce([Int]()) { var

accum = \$0 accum.append(\$1 * \$1) return accum } let evens2 = list.reduce([Int]()){ if \$1 % 2 == 0 { var accum = \$0 accum.append(\$1) return accum } else { return \$0 } }
17. MAPPING AND FILTERING IS MORE EXPRESSIVE let sumOfSquaresOfEvenNumbers = list

.filter{ \$0 % 2 == 0 } .map { \$0 * \$0 } .reduce(0, combine: +)

19. A monad is a monoid in the category of endofunctors,

what’s the problem? -- Philip Wadler1 1 Not really – see http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html

22. ▸ Optional is a context that contains a value or

the lack of a value

an order
24. ▸ Result is the context that has a value or

an error in getting that value

solution"
28. typealias is useful for making code clearer. func decode(json: [String

: AnyObject]) -> MyType { ... } or typealias JSONDictionary = [String : AnyObject] func decode(json: JSONDictionary) -> myType { ... }
29. It can make higher order function declarations easier to read.

// Taken from AlamoFire typealias JSONResponseHandler = (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> () // Define a common completion block with specific handler func responseHandlerWithCompletion(completion: Result<MyType>) -> JSONResponseHandler { ... }

the types and transformations of those types, before writing any code.

32. func shuffle(deck: Deck) -> Deck { ... } func deal(deck:

Deck, toPlayers: [Player]) -> [Hand] { ... } func winner(hands: [Hand]) -> Player { ... }

34. module Main where import Control.Monad import Numeric factoryTimes :: Double

-> Double -> [Double] factoryTimes c f = 0.0 : [ c / (2.0 + k * f) | k <- [0.0, 1.0 ..]] productionTimes :: Double -> Double -> [Double] productionTimes x f = [ x / (2.0 + k * f) | k <- [0.0, 1.0 ..]] times :: Double -> Double -> Double -> [Double] times c f x = zipWith (+) production factory where production = productionTimes x f factory = scanl1 (+) \$ factoryTimes c f firstMinimum :: [Double] -> Double firstMinimum (x:y:ys) = if x < y then x else firstMinimum (y:ys) solve :: Double -> Double -> Double -> Double solve c f x = firstMinimum \$ times c f x main :: IO () main = do t <- getLine forM_ [1..read t :: Int] \$ \i -> do [c, f, x] <- fmap (map read . words) getLine let result = solve c f x putStrLn \$ concat ["Case #", show i, ": ", Numeric.showFFloat (Just 7) result ""]

36. ▸ Don't have state, have functions that return values; although

this is easier said than done. ▸ Higher order functions can be used to reduce duplication in code.
37. ▸ Aim to write small, pure functions with no side

effects. ▸ Avoid mixing pure and impure code. ▸ Aim to write small, obviously correct functions.
38. Composition infix operator >>> { associativity right precedence 170 }

func >>> <A, B, C>(f: B -> C, g: A -> B) -> A -> C { return { x in f(g(x)) } }
39. Map on Optionals infix operator <^> { associativity left }

func <^> <A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return nil } }
40. Applicative on Optionals infix operator <*> { associativity left }

func <*> <A, B>(lhs: (A -> B)?, rhs: A?) -> B? { if let f = lhs { if let x = rhs { return f(x) } } return nil }
41. Bind on Optionals infix operator >>== { associativity left precedence

150 } func >>== <A, B>(a:A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return nil } }

43. OOP concerns data objects and operations on those data objects

— My naive definition
44. "Why are methods of protocols defined outside the Type?" struct

SomeType: Equatable { ... } func ==(lhs: ...
45. If we are supposed to favour immutability, shouldn't we be

moving away from classes?
46. Have you ever created a class with nothing but class

functions just to keep related code together?
47. Have you ever carefully exposed only the methods that were

safe to call on your objects, keeping other methods private?
48. If you have pure functions (no side effects, same inputs,

same outputs) is it worth worrying about their access modifiers? Can you make them bare functions instead?
49. If the functions can be grouped together into a logical

set of functionality, could a protocol be defined to encompass that functionality instead?
50. Programming to an interface was a recommendation even in the

times of Objective-C. The stronger type system in Swift makes it even more attractive.

58. WITH COCOA WE HAVE THE CHOICE OF TWO DIFFERENT APPROACHES

TO THE SAME PROBLEM SPACE.

60. I want to write code like this: static func decode(object:

JSON) -> DateWithTimeZone? { return jsonDictionary(object) >>== { dict in DateWithTimeZone.create <^> dict[dateWithTimeFormatKey(.Date)] >>== jsonDate <*> dict[dateWithTimeFormatKey(.TimeZone)] >>== jsonTimeZone } } It looks complex because it's unfamiliar, but it's clearer than having a pyramid of doom.
61. This stuff is hard. But compared with what we already

do and what we aspire to do; it's perfectly within our grasp.
62. THANK YOU & HAVE A GREAT WEEK! ABIZER NASIR |

@ABIZERN | ABIZERN.ORG