functional programming - gasi · functional programming or: how i learned to stop worrying and love...

89
Fun Profit* Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica March 17, 2017

Upload: others

Post on 13-Aug-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Fun Profit*

Functional Programming

Or: How I Learned to Stop Worrying and Love Shipping Haskell Code

&for

*after accomplishing step 2: ???Daniel Gąsienica March 17, 2017

Page 2: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Amuse-BouchesBackground

Food for Thought*

*Opinions

Page 3: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

What this talk is about

Page 4: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

What this talk is not about

Page 5: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Background

Page 6: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ETH 2011

Page 7: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica
Page 8: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica
Page 9: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Thanksgiving 2015

Photo: https://commons.wikimedia.org/wiki/User:Braniff747SP

Page 10: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

zoomhub

Page 11: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ZoomHub

http://zoomhub.net?url=http://www.rhysy.net/Timeline/LargeTimeline.png

Image URL

Zoomable Image

http://zoomhub.net/K4J1

Page 12: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Amuse-Bouches

Page 13: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Immutability &

The Value of Values

Page 14: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

The Pain

Page 15: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

* Fixed in recent versions of WebKit/Chrome

*

Page 16: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

The Bugs

Page 17: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

var config = { //... baseURL: 'http://api.zynga.com', //...}

function bar(config) { console.log(config.baseURL.length)}

Page 18: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

var config = { //... baseURL: 'http://api.zynga.com', //...}

function bar(config) { // NPE console.log(config.baseURL.length)}

Page 19: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

var config = { //... baseURL: 'http://api.zynga.com', //...}

function foo(config) { // Don’t ask me why but… delete config.baseURL}

function bar(config) { // NPE console.log(config.baseURL.length)}

Page 20: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica
Page 21: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

The Confusion

Page 22: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> 1 === 1true

> true === truetrue

> "hello" === "hello"true

Page 23: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> 1 === 1true

> true === truetrue

> "hello" === "hello"true

> [] === []false

> [1, 2] === [1, 2]false

> {} === {}false

> {"a": "b"} === {"a": "b"}false

Page 24: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> 1 === 1true

> true === truetrue

> "hello" === "hello"true

> 1 == 1True

> True == TrueTrue

> "hello" == "hello"True

> [] == []True

> [1, 2] == [1, 2]True

> Map.fromList [] == Map.fromList []True

> Map.fromList [("a", "b")] == Map.fromList [("a", "b")]True

> [] === []false

> [1, 2] === [1, 2]false

> {} === {}false

> {"a": "b"} === {"a": "b"}false

Page 25: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> let a = [3, 1, 2]

> let b = a.sort()

> b[1, 2, 3]

Page 26: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> let a = [3, 1, 2]

> let b = a.sort()

> b[1, 2, 3]

> a[1, 2, 3]

Page 27: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

> let a = [3, 1, 2]

> let b = sort a

> b[1, 2, 3]

> a[3, 1, 2]

> let a = [3, 1, 2]

> let b = a.sort()

> b[1, 2, 3]

> a[1, 2, 3]

— space = function— application— i.e. JavaScript: sort(a)

Page 28: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ConclusionAbandon distinction between

values and references and treat everything as

immutable values.

Page 29: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

https://www.infoq.com/presentations/Value-Values

Page 30: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

nullThe Billion-Dollar Mistake

Page 31: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

“I call it my billion-dollar mistake. It was the invention of

the null reference in 1965.”— C. A. R. Hoare

Page 32: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

boolean string number object

Page 33: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

boolean string number object

any

Page 34: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

boolean string number object

any

Page 35: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

boolean string number object

any

null

Page 36: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

boolean string number object

any

null

Page 37: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

let names = ["Aseem", "Matt"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name.toUpperCase())// > MATT

Page 38: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

let names = ["Aseem", "Matt"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name.toUpperCase())// > MATT

let names = ["Aseem"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name.toUpperCase())

// console.log(name.toUpperCase())// ^//// TypeError: Cannot read property// 'toUpperCase' of undefined

Page 39: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do let names = ["Aseem", "Matt"] isCool x = length x <= 4 name = find isCool names print (toUpperCase name)

-- null.hs:5:22:-- Coudn't match expected type ‘String’-- with actual type ‘Maybe String’-- In the first argument of ‘toUpperCase’,-- namely ‘name’-- In the first argument of ‘print’,-- namely ‘(toUpperCase name)’

let names = ["Aseem", "Matt"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name.toUpperCase())// > MATT

let names = ["Aseem"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name.toUpperCase())

// console.log(name.toUpperCase())// ^//// TypeError: Cannot read property// 'toUpperCase' of undefined

Page 40: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

find :: (a -> Bool) -> [a] -> Maybe aArray<A>.find( predicate: (value: A) => boolean): A | null

Page 41: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data Maybe a = Just a | Nothing

Page 42: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data Maybe a = Just a | Nothing

foo :: Maybe Intfoo = Just 5orfoo = Nothing

bar :: Maybe Stringbar = Just "Hello"or bar = Nothing

Page 43: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

let names = ["Aseem"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name ? name.toUpperCase() : "nuddin")// nuddin

Page 44: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do let names = ["Aseem"] isCool x = length x <= 4 name = find isCool names print (case name of Just s -> toUpperCase s Nothing -> "nuddin" )-- nuddin

let names = ["Aseem"]let isCool = x => x.length <= 4let name = names.find(isCool)console.log(name ? name.toUpperCase() : "nuddin")// nuddin

Page 45: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ConclusionUnhandled nulls can

cause unexpected runtime errors.

Explicitly model the presence and absence of values and

enforce handling of all cases.

Page 46: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Types

Page 47: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

First-Class Compile-Time

Type Safety

Page 48: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data User = User { userId :: UserId , userEmail :: Email } deriving Show

newtype Email = Email String deriving Shownewtype UserId = UserId String deriving Show

createUser :: UserId -> Email -> UsercreateUser userId userEmail = User { userId = userId, userEmail = userEmail }

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

{- types-user.hs:16:21: Couldn't match expected type ‘UserId’ with actual type ‘Email’ In the first argument of ‘createUser’, namely ‘email’ In the first argument of ‘print’, namely ‘(createUser email userId)’

types-user.hs:16:27: Couldn't match expected type ‘Email’ with actual type ‘UserId’ In the second argument of ‘createUser’, namely ‘userId’ In the first argument of ‘print’, namely ‘(createUser email userId)’-}

Page 49: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

class User { private userId: string private userEmail: string

constructor(userId: string, userEmail: string) { this.userId = userId this.userEmail = userEmail }}

// Mainlet email = '[email protected]'let userId = '3490'

console.log(new User(email, userId))// User { userId: '[email protected]', userEmail: '3490' }

Page 50: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data User = User { userId :: UserId , userEmail :: Email } deriving Show

class User { private userId: string private userEmail: string

constructor(userId: string userEmail: string) { this.userId = userId this.userEmail = userEmail }}

// `deriving Show` is explicit generation// of `Object.prototype.toString()`

Page 51: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

createUser :: UserId -> Email -> UsercreateUser userId userEmail = User { userId = userId , userEmail = userEmail }

class User { private userId: string private userEmail: string

constructor(userId: string, userEmail: string) { this.userId = userId this.userEmail = userEmail }}

// function createUser(// userId: UserId,// userEmail: Email// ): User

Page 52: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

{- types-user.hs:16:21: Couldn't match expected type ‘UserId’ with actual type ‘Email’ In the first argument of ‘createUser’, namely ‘email’ In the first argument of ‘print’, namely ‘(createUser email userId)’

types-user.hs:16:27: Couldn't match expected type ‘Email’ with actual type ‘UserId’ In the second argument of ‘createUser’, namely ‘userId’ In the first argument of ‘print’, namely ‘(createUser email userId)’-}

// Mainlet email = '[email protected]'let userId = '3490'

console.log(new User(email, userId))// User { userId: '[email protected]',// userEmail: '3490' }

Page 53: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

(Awkward) ‘Solution’

Page 54: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

class User { private userId: UserId private userEmail: Email

constructor(userId: UserId, userEmail: Email) { this.userId = userId this.userEmail = userEmail }}

type Email = string & {_emailBrand: any}type UserId = string & {_userIdBrand: any}

// Mainlet email = '[email protected]' as Emaillet userId = '3490' as UserId

console.log(new User(email, userId))// Argument of type 'Email' is not assignable to parameter of type 'UserId'.// Type 'Email' is not assignable to type '{ _userIdBrand: any; }'.// Property '_userIdBrand' is missing in type 'Email'.

Page 55: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

newtype Email = Email String deriving Shownewtype UserId = UserId String deriving Show

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

Page 56: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

type Email = string & {_emailBrand: any}type UserId = string & {_userIdBrand: any}

// Mainlet email = '[email protected]' as Emaillet userId = '3490' as UserIdconsole.log(new User(email, userId))

newtype Email = Email String deriving Shownewtype UserId = UserId String deriving Show

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

Page 57: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

type Email = string & {_emailBrand: any}type UserId = string & {_userIdBrand: any}

// Mainlet email = '[email protected]' as Emaillet userId = '3490' as UserIdconsole.log(new User(email, userId))

newtype Email = Email String deriving Shownewtype UserId = UserId String deriving Show

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

Language Feature

Page 58: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

type Email = string & {_emailBrand: any}type UserId = string & {_userIdBrand: any}

// Mainlet email = '[email protected]' as Emaillet userId = '3490' as UserIdconsole.log(new User(email, userId))

newtype Email = Email String deriving Shownewtype UserId = UserId String deriving Show

-- Mainmain = do let email = Email "[email protected]" userId = UserId "3490" print (createUser email userId)

Language Feature Hack

Page 59: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

‘Built-in’ Types

Page 60: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data Bool = True | False

// function and(a: boolean, b: boolean): booleanand :: Bool -> Bool -> Booland True True = Trueand _ _ = False

// function or(a: boolean, b: boolean): booleanor :: Bool -> Bool -> Boolor False False = Falseor _ _ = True

Page 61: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

data Bool = True | False

(&&) :: Bool -> Bool -> Bool(&&) True True = True(&&) _ _ = False

(||) :: Bool -> Bool -> Bool(||) False False = False(||) _ _ = True

// Define: (&&)// Use: True && False

Page 62: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Security

Page 63: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

“Make sure we never store plaintext passwords

in our database.”

Page 64: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

newtype PlainTextPassword = PlainTextPassword String deriving Shownewtype HashedPassword = HashedPassword String deriving Show

getPassword :: IO PlainTextPasswordgetPassword = do s <- getLine return (PlainTextPassword s)

hashPassword :: PlainTextPassword -> HashedPasswordhashPassword (PlainTextPassword s) = HashedPassword ((reverse s) ++ "$SALT$")

storePassword :: HashedPassword -> IO ()storePassword (HashedPassword s) = putStrLn s

-- Mainmain = do putStrLn "Enter password please:" p <- getPassword

putStrLn "\nStored the following hashed password:" storePassword p

-- types-security.hs:21:17:-- Couldn't match expected type ‘HashedPassword’-- with actual type ‘PlainTextPassword’-- In the first argument of ‘storePassword’, namely ‘p’-- In a stmt of a 'do' block: storePassword p

Page 65: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

newtype PlainTextPassword = PlainTextPassword String deriving Shownewtype HashedPassword = HashedPassword String deriving Show

getPassword :: IO PlainTextPasswordgetPassword = do s <- getLine return (PlainTextPassword s)

hashPassword :: PlainTextPassword -> HashedPasswordhashPassword (PlainTextPassword s) = HashedPassword ((reverse s) ++ "$SALT$")

storePassword :: HashedPassword -> IO ()storePassword (HashedPassword s) = putStrLn s

-- Mainmain = do putStrLn "Enter password please:" p <- getPassword

putStrLn "\nStored the following hashed password:" storePassword (hashPassword p) —- before: `storePassword p`

-- Enter password please:-- passw0rd---- Stored the following hashed password:-- dr0wssap$SALT$

Page 66: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ConclusionTypes can help prevent many

errors at compile-time. They are a versatile and powerful

tool to model your domain.

Page 67: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Abstraction &

Type Classes

Page 68: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

map

Page 69: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

console.log([1, 2, 3].map(x => x * 3))// [3, 6, 9]

Page 70: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

// Array<A>.map<B>(fn: (value: A) => B): Array<B>console.log([1, 2, 3].map(x => x * 3))// [3, 6, 9]

Page 71: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do -- map :: (a -> b) -> [a] -> [b] print (map (\x -> x * 3) [1, 2, 3]) -- [3, 6, 9]

Page 72: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do -- map :: (a -> b) -> [a] -> [b] print (map (3*) [1, 2, 3]) -- [3, 6, 9]

main = do -- map :: (a -> b) -> [a] -> [b] print (map (\x -> x * 3) [1, 2, 3]) -- [3, 6, 9]

Page 73: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do -- map :: (a -> b) -> [a] -> [b] print (map (3*) [1, 2, 3]) -- [3, 6, 9]

// Array<A>.map<B>(// fn: (value: A) => B// ): Array<B>console.log([1, 2, 3].map(x => x * 3))// [3, 6, 9]

Page 74: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Array<A>.map<B>(fn: (value: A) => B): Array<B>

Page 75: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

F<A>.fmap<B>(fn: (value: A) => B): F<B>

// Container `F`

// `fmap` is generic `map` that// works on any container `F`

Page 76: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

class Functor f where fmap :: (a -> b) -> f a -> f b

—- Container `f`

—- `fmap` is generic `map` that—- works on any container `f`

Page 77: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

instance Functor [] where fmap fn [] = [] fmap fn (x:xs) = (fn x) : (fmap fn xs)

—- x = first element of the list —- xs = rest (tail) of the list

—- (:) = prepend list element

Page 78: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

instance Functor [] where fmap = map

Page 79: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

instance Functor Maybe where fmap fn Nothing = Nothing fmap fn (Just x) = Just (fn x)

Page 80: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

main = do -- List print (fmap (3*) [1, 2, 3]) -- > [3, 6, 9]

-- Maybe print (fmap (3*) Nothing) -- > Nothing print (fmap (3*) (Just 2)) -- > Just 6

-- IO -- getLine :: IO String putStrLn "\nWhat is your name?" message <- fmap ("Hello, " ++) getLine putStrLn message -- > What is your name? -- > Daniel -- > "Hello, Daniel"

-- Async putStrLn "\nSay something…" asyncPrompt <- async getLine asyncMessage <- wait (fmap ("Async: " ++) asyncPrompt) putStrLn asyncMessage -- > Say something… -- > Yo yo -- > Async: Yo yo

Page 81: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

ConclusionExpressive languages allow

developers to describe better abstractions.

Type classes are a mechanism for

abstracting common behaviors between different types.

Page 82: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Food for Thought

Page 83: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Impure Shell &

Pure Core

Page 84: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Pure Core • business logic • data transformation • validation • parsing • encoding / decoding

Impure Shell • user input • networking • file IO • database • randomness • rendering

Page 85: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Pure Core • lexical analysis • syntax analysis • type checking • optimize code • generate code

Example: CompilerImpure Shell • read CLI options • read environment

variables • read source files • write binary

Page 86: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

CONTROVERSIAL CONTENTADVISORYP A R E N T A L

Page 87: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Sound Foundation > Weak Ecosystem

Page 88: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Stay Hungry

Page 89: Functional Programming - Gasi · Functional Programming Or: How I Learned to Stop Worrying and Love Shipping Haskell Code & for *after accomplishing step 2: ??? Daniel Gąsienica

Q&A

“The only thing necessary for the triumph of [bad technology] is for

good men to do nothing.”

“All [bad technology] needs to gain a foothold is for people of good conscience

to remain silent.”