320

My talk from AltConf 2015

June 10, 2015

## Transcript

1. ### WHAT HASKELL TEACHES ME ABOUT WRITING SWIFT Abizer Nasir |

@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.

13. None

16. ### 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: +)
17. ### 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 } }
18. ### MAPPING AND FILTERING IS MORE EXPRESSIVE let sumOfSquaresOfEvenNumbers = list

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

20. ### 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

23. ### ▸ Optional is a context that contains a value or

the lack of a value

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

an error in getting that value

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

: AnyObject]) -> MyType { ... } or typealias JSONDictionary = [String : AnyObject] func decode(json: JSONDictionary) -> myType { ... }
30. ### 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 { ... }
31. ### ▸ You can reason about your problem in terms of

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

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

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

35. ### 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 ""]

37. ### ▸ 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.
38. ### ▸ Aim to write small, pure functions with no side

effects. ▸ Avoid mixing pure and impure code. ▸ Aim to write small, obviously correct functions.
39. ### 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)) } }
40. ### 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 } }
41. ### 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 }
42. ### 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 } }

44. ### OOP concerns data objects and operations on those data objects

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

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

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

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

safe to call on your objects, keeping other methods private?
49. ### 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?
50. ### If the functions can be grouped together into a logical

set of functionality, could a protocol be defined to encompass that functionality instead?
51. ### 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.

59. ### WITH COCOA WE HAVE THE CHOICE OF TWO DIFFERENT APPROACHES

TO THE SAME PROBLEM SPACE.

61. ### 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.
62. ### This stuff is hard. But compared with what we already

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

@ABIZERN | ABIZERN.ORG