Pragmatism, Puritanism and Functional Programming Ben Moseley - - PowerPoint PPT Presentation

pragmatism puritanism and functional programming
SMART_READER_LITE
LIVE PREVIEW

Pragmatism, Puritanism and Functional Programming Ben Moseley - - PowerPoint PPT Presentation

Pragmatism, Puritanism and Functional Programming Ben Moseley ben@moseley.name TechMesh - 4 December Pragmatism, Puritanism and Functional Programming Ben Moseley ben@moseley.name TechMesh - 4 December 2012 Pragmatism, Puritanism and


slide-1
SLIDE 1

Pragmatism, Puritanism and Functional Programming

TechMesh - 4 December

Ben Moseley — ben@moseley.name

slide-2
SLIDE 2

Pragmatism, Puritanism and Functional Programming

TechMesh - 4 December 2012

Ben Moseley — ben@moseley.name

slide-3
SLIDE 3

Pragmatism, Puritanism and Functional Programming

TechMesh - 4 December 2012

Ben Moseley — ben@moseley.name

slide-4
SLIDE 4

Why am I here?

slide-5
SLIDE 5

Why am I here?

✤ Software in Industry ...

slide-6
SLIDE 6

Why am I here?

✤ Software in Industry ... ✤ ... is broken.

slide-7
SLIDE 7

Why am I here?

✤ Software in Industry ... ✤ ... is broken. ✤ ... because it’s too complex !

slide-8
SLIDE 8

Why am I here?

✤ Software in Industry ... ✤ ... is broken. ✤ ... because it’s too complex ! ✤ My perspective on why FP techniques can help ✤ Based on 8 years of Haskell (5 full-time commercial)

slide-9
SLIDE 9

Haskell...

slide-10
SLIDE 10

Haskell...

✤ Haskell makes programs: ✤ Simpler to Write ✤ Simpler to Read (ie understand)

slide-11
SLIDE 11

Haskell...

✤ Haskell makes programs: ✤ Simpler to Write ✤ Simpler to Read (ie understand) ✤ Is Haskell simple?

slide-12
SLIDE 12

Haskell...

✤ Haskell makes programs: ✤ Simpler to Write ✤ Simpler to Read (ie understand) ✤ Is Haskell simple? ✤ Is Haskell easy?

slide-13
SLIDE 13

A Better Language?

slide-14
SLIDE 14

What is important about FP?

✤ Purity ✤ Type Systems ✤ Higher Order Functions (HOFs) ✤ Laziness ✤ Extensive abstract libraries

slide-15
SLIDE 15

What makes FP hard to learn?

slide-16
SLIDE 16

What makes FP hard to learn?

✤ Purity ✤ Type Systems ✤ HOFs ✤ Laziness ✤ Extensive abstract libraries

slide-17
SLIDE 17

Purity

“The functional programmer sounds rather like a medieval monk, denying himself the pleasures of life in the hope that it will make him virtuous.”

  • - John Hughes [~1984]
slide-18
SLIDE 18

Modularity

✤ We build systems by naming and assembling chunks of code ✤ Interested in: ✤ Result of a chunk ✤ What a chunk Does

var y = chunk1(a,b); var z = chunk2(c); chunk3(x); chunk4(y,z);

slide-19
SLIDE 19

Read & Understand...

slide-20
SLIDE 20

Read & Understand...

var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); v0.9

slide-21
SLIDE 21

Read & Understand...

var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); v1.0

slide-22
SLIDE 22

Read & Understand...

var y = chunk2(c); var x = chunk1(a,b); chunk3(x,y); var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); v1.0 v2.0

slide-23
SLIDE 23

Read & Understand...

var y = chunk2(c); var x = chunk1(a,b); chunk3(x,y); var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); var x = chunk4(a,b); var y = chunk4(a,b); chunk5(x,y); var x = chunk4(a,b); var y = x; chunk5(x,y); v1.0 v2.0

slide-24
SLIDE 24

What is Purity?

var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); var x = chunk4(a,b); var y = chunk4(a,b); chunk5(x,y);

slide-25
SLIDE 25

What is Purity?

var x = chunk1(a,b); var y = chunk2(c); chunk3(x,y); var x = chunk4(a,b); var y = chunk4(a,b); chunk5(x,y); f :: A -> B

slide-26
SLIDE 26

Purity Pitfall 1 - Effects

var y = chunk1(a,b); var z = chunk1(a,b); chunk3(x); chunk4(y,z); f :: A -> B f :: (A,s) -> (B,s) var (y,s2) = chunk1(a,b,s); var (z,s3) = chunk1(a,b,s2); var s4 = chunk3(x,s3); var s5 = chunk4(y,z,s4);

✤ Pitfall 1 : Sometimes you want chunks which have state:

slide-27
SLIDE 27

Purity Pitfall 1 - Effects

var y = chunk1(a,b); var z = chunk2(c); chunk3(x); chunk4(y,z); f :: A -> B f :: A -> Maybe B

✤ Pitfall 1 : Sometimes you need chunks which can fail:

case chunk1(a,b) of Just y -> case chunk2(c) of Just z -> case chunk3(x) of Just () -> case chunk4(y,z) ...

slide-28
SLIDE 28

Purity Pitfall 1 - Effects

✤ Pitfall 1b : The syntax is quite verbose

f :: (A,s) -> (B,s) var (y,s2) = chunk1(a,b,s); var (z,s3) = chunk1(a,b,s2); var s4 = chunk3(x,s3); var s5 = chunk4(y,z,s4);

slide-29
SLIDE 29

Purity Pitfall 1 - Effects

✤ Pitfall 1b : The syntax is quite verbose

f :: (A,s) -> (B,s) var (y,s2) = chunk1(a,b,s); var (z,s3) = chunk1(a,b,s2); var s4 = chunk3(x,s3); var s5 = chunk4(y,z,s4); f :: A -> State s B do y <- chunk1(a,b) z <- chunk1(a,b) chunk3(x) chunk4(y,z)

slide-30
SLIDE 30

Purity - Is this all a con ?

✤ SIDE-EFFECTS pitfall is avoided by: ✤ Take them away.... ✤ ..... put them back

slide-31
SLIDE 31

Purity - Is this all a con ?

slide-32
SLIDE 32

Purity - Is this all a con ?

✤ SIDE-EFFECTS pitfall is avoided by: ✤ Take them away.... ✤ ..... put them back if necessary

slide-33
SLIDE 33

Purity - Is this all a con ?

✤ SIDE-EFFECTS pitfall is avoided by: ✤ Take them away.... ✤ ..... put them back if necessary ✤ ... in a restricted way that makes the code simpler to understand!!

slide-34
SLIDE 34

Purity - Is this all a con ?

✤ SIDE-EFFECTS pitfall is avoided by: ✤ Take them away.... ✤ ..... put them back if necessary ✤ ... in a restricted way that makes the code simpler to understand!!

  • 1. Each chunk uses only the effects it needs
  • 2. The exact effects are visible in the type
  • 3. We can now control how different effects interact
slide-35
SLIDE 35

Purity Pitfall 2 - Equality

✤ Yes .... but .... ✤

var y =

Mul 3 Add "x" Sub 3 "y"

var x =

Mul 3 Add "x" Sub 3 "y"

x == y

slide-36
SLIDE 36

Purity Pitfall 2 - Equality

✤ Yes .... but .... ✤ ... slow to find out

var y =

Mul 3 Add "x" Sub 3 "y"

var x =

Mul 3 Add "x" Sub 3 "y"

x == y

slide-37
SLIDE 37

Purity Pitfall 2 - Equality

✤ POINTER EQUALITY pitfall is avoided by: ✤ Take it away.... ✤ ..... put it back if necessary ✤ ... in a restricted way that makes the code simpler to understand!! ✤ Explicit ✤ Localized

slide-38
SLIDE 38

Purity Pitfall 3 - Identity

✤ CAD system

slide-39
SLIDE 39

Purity Pitfall 3 - Identity

✤ CAD system

slide-40
SLIDE 40

Purity Pitfall 3 - Identity

✤ CAD system

Circle Line Line Circle

slide-41
SLIDE 41

ID: 1001 ID: 1002 ID: 1003 ID: 1004 Centre: 0,0 Radius: 100 Circle Centre: 250,0 Radius: 20 Circle

Purity Pitfall 3 - Identity

✤ CAD system

Circle Line Line Circle CircleOne: 1001 CircleTwo: 1002 CircleOne: 1001 CircleTwo: 1002 Line Line

slide-42
SLIDE 42

ID: 1001 ID: 1002 ID: 1003 ID: 1004 Centre: 0,0 Radius: 100 Circle Centre: 250,0 Radius: 20 Circle

Purity Pitfall 3 - Identity

✤ CAD system

Circle Line Line Circle Centre: 250,0 Radius: 100 Circle CircleOne: 1001 CircleTwo: 1002 CircleOne: 1001 CircleTwo: 1002 Line Line

slide-43
SLIDE 43

Purity Pitfall 3 - Identity

✤ IDENTITY pitfall is avoided by: ✤ Take it away.... ✤ ..... put it back if necessary ✤ ... in an explicit way that makes the code simpler to understand!!

slide-44
SLIDE 44

Purity - Pitfalls

  • 1. Sometimes you really want Side Effects (eg Failure / Mutability)
  • 2. Sometimes you really want Pointer Equality
  • 3. Sometimes you really want Identity
slide-45
SLIDE 45

Purity - Pitfalls

  • 1. Sometimes you really want Side Effects (eg Failure / Mutability)
  • 2. Sometimes you really want Pointer Equality
  • 3. Sometimes you really want Identity
  • 4. Learning Curve - Need to think in a different (unnatural) way
slide-46
SLIDE 46

T ype Systems

✤ Static vs Dynamic Types ✤ Benefits... ✤ Pitfalls

slide-47
SLIDE 47

T ype Systems - Confusion

✤ Statically Typed Languages are Dynamically Typed Languages ✤ ... with an extra feature: ✤ ... any “Classification” you make can be Static (or Dynamic) ✤ ... typically use this in their std libs

slide-48
SLIDE 48

data Bool = True | False

T ypes in Haskell

slide-49
SLIDE 49

T ypes in Haskell

data Int = ... data Bool = True | False data Float = ... data String = ...

slide-50
SLIDE 50

Dynamic T ypes in Haskell

data Value = TagInt Int | TagFloat Float | TagBool Bool | TagString String

slide-51
SLIDE 51

FilePaths 1 - Strings vs Paths

Strings vs Paths

slide-52
SLIDE 52

FilePaths 1 - Strings vs Paths

String Strings vs Paths No Distinction

slide-53
SLIDE 53

FilePaths 1 - Strings vs Paths

String appendPath :: (String, String) -> String Strings vs Paths No Distinction

slide-54
SLIDE 54

appendPath (“\usr\bm”, “bar.csv”)

FilePaths 1 - Strings vs Paths

String appendPath :: (String, String) -> String Strings vs Paths No Distinction

slide-55
SLIDE 55

appendPath (“line1\n line2\r\n...”, “bar.csv”)

FilePaths 1 - Strings vs Paths

String appendPath :: (String, String) -> String Strings vs Paths No Distinction ...no error

slide-56
SLIDE 56

FilePaths 1 - Strings vs Paths

String appendPath :: (Value, Value) -> Value data Value = TagInt Int | TagFloat Float | TagBool Bool | TagString String | TagPath String Runtime Distinction Strings vs Paths No Distinction

slide-57
SLIDE 57

FilePaths 1 - Strings vs Paths

String appendPath :: (Value, Value) -> Value data Value = TagInt Int | TagFloat Float | TagBool Bool | TagString String | TagPath String Runtime Distinction Strings vs Paths No Distinction appendPath (TagString “line1\n line2\r\n...”, TagPath “bar.csv”) ...dynamic error

slide-58
SLIDE 58

FilePaths 1 - Strings vs Paths

String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction

slide-59
SLIDE 59

FilePaths 1 - Strings vs Paths

data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction

slide-60
SLIDE 60

FilePaths 1 - Strings vs Paths

data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Path “bar.csv” :: Path Path “/usr/bm” :: Path

slide-61
SLIDE 61

FilePaths 1 - Strings vs Paths

data Path = Path String appendPath :: (Path, Path) -> Path Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Path “bar.csv” :: Path Path “/usr/bm” :: Path

slide-62
SLIDE 62

appendPath (“line1\n line2\r\n...”, Path “bar.csv”)

FilePaths 1 - Strings vs Paths

data Path = Path String appendPath :: (Path, Path) -> Path Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction ...static error Path “bar.csv” :: Path Path “/usr/bm” :: Path

slide-63
SLIDE 63

appendPath ( Path “/usr/bm”, Path “bar.csv”)

FilePaths 1 - Strings vs Paths

data Path = Path String appendPath :: (Path, Path) -> Path Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Path “bar.csv” :: Path Path “/usr/bm” :: Path

slide-64
SLIDE 64

FilePaths 1 - Strings vs Paths

appendPath :: (Path, Path) -> Path appendPath ( Path “foo.txt”, Path “bar.csv”) data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction ...no error Path “bar.csv” :: Path Path “/usr/bm” :: Path

slide-65
SLIDE 65

appendPath ( Path “foo.txt”, Path “bar.csv”)

FilePaths 2 - File vs Dir Paths

data Path = FilePath String | DirPath String appendPath :: (Path, Path) -> Path Runtime File Paths vs Dir Paths data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction

slide-66
SLIDE 66

appendPath (FilePath “foo.txt”, FilePath “bar.csv”)

FilePaths 2 - File vs Dir Paths

data Path = FilePath String | DirPath String appendPath :: (Path, Path) -> Path Runtime File Paths vs Dir Paths data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction ...dynamic error

slide-67
SLIDE 67

FilePaths 2 - File vs Dir Paths

data Path = Path String Path “fred.csv” :: Path Path “/usr” :: Path data Path = FilePath String | DirPath String Runtime File Paths vs Dir Paths No Distinction data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction appendPath :: (Path , Path ) -> Path

slide-68
SLIDE 68

FilePaths 2 - File vs Dir Paths

data Path fd = Path String Path “fred.csv” :: Path Path “/usr” :: Path data Path = FilePath String | DirPath String Runtime File Paths vs Dir Paths data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Compile time appendPath :: (Path , Path ) -> Path

slide-69
SLIDE 69

FilePaths 2 - File vs Dir Paths

data Path fd = Path String Path “fred.csv” :: Path File Path “/usr” :: Path Dir data Path = FilePath String | DirPath String Runtime File Paths vs Dir Paths data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Compile time appendPath :: (Path , Path ) -> Path

slide-70
SLIDE 70

FilePaths 2 - File vs Dir Paths

data Path fd = Path String Path “fred.csv” :: Path File Path “/usr” :: Path Dir data Path = FilePath String | DirPath String Runtime File Paths vs Dir Paths data Path = Path String Compile time String data Value =...| TagString String | TagPath String Runtime Strings vs Paths No Distinction Compile time appendPath :: (Path Dir, Path fd) -> Path fd

slide-71
SLIDE 71

Static T ypes - Sliding Scale

data Path fd = Path String String data Path = FilePath String | DirPath String Runtime File Paths vs Dir Paths Strings vs Paths No Distinction Compile time data Path = Path String No Distinction data Path = Path String data Value =...| TagString String | TagPath String Compile time Runtime

slide-72
SLIDE 72

Static T ype Systems - Benefits

✤ Make code simpler to write ✤ detect errors earlier ✤ the first thing you write - a design language ✤ Refactoring, IDEs, Performance

slide-73
SLIDE 73

Static T ype Systems - Benefits

✤ Make code simpler to read ✤ Help locate bugs (in type-correct code !) ✤ Help understand normal code ✤ Help understand very abstract code ✤ Document side-effects

slide-74
SLIDE 74

T ypes: Assumptions & Guarantees

mychunk :: [Int] -> [Int] mychunk = ...

slide-75
SLIDE 75

T ypes: Assumptions & Guarantees

mychunk :: [Int] -> [Int] mychunk = ...

slide-76
SLIDE 76

T ypes: Assumptions & Guarantees

mychunk :: [Int] -> [Int] mychunk = ...

slide-77
SLIDE 77

T ypes: Assumptions & Guarantees

mychunk :: [a] -> [a] mychunk = ...

slide-78
SLIDE 78

T ypes: Assumptions & Guarantees

mychunk :: [a] -> [a] mychunk = ...

slide-79
SLIDE 79

T ypes: Assumptions & Guarantees

mychunk :: [a] -> [a] mychunk = ...

slide-80
SLIDE 80

T ypes: Assumptions & Guarantees

mychunk :: Eq a => [a] -> [a] mychunk = ...

slide-81
SLIDE 81

T ypes: Assumptions & Guarantees

mychunk :: Num a => [a] -> [a] mychunk = ...

slide-82
SLIDE 82

T ypes: Assumptions & Guarantees

mychunk :: Typeable a => [a] -> [a] mychunk = ...

slide-83
SLIDE 83

T ypes: Assumptions & Guarantees

mychunk :: [a] -> [a] mychunk = ...

slide-84
SLIDE 84

processWith f = g (f [100,101]) g xs = ...

T ypes: Locating Bugs

slide-85
SLIDE 85

T ypes: Locating Bugs

processWith :: (forall a. [a] -> [a]) -> [Int] processWith f = g (f [100,101]) g :: [Int] -> [Int] g xs = ...

slide-86
SLIDE 86

T ypes: Locating Bugs

processWith :: (forall a. [a] -> [a]) -> [Int] processWith f = g (f [100,101]) g :: [a] -> [a] g xs = ...

slide-87
SLIDE 87

T ypes: Understanding Code

trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

slide-88
SLIDE 88

trans :: [(Int,Int)] -> [(Int,Int)] -> [(Int,Int)] trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

T ypes: Understanding Code

slide-89
SLIDE 89

trans :: Eq b => [(b, b)] -> [(b, b)] -> [(b, b)] trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

T ypes: Understanding Code

slide-90
SLIDE 90

trans :: Eq b => [(b, b)] -> [(b, b)] -> [(b, b)] trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

T ypes: Understanding Code

slide-91
SLIDE 91

trans :: Eq b => [(a, b)] -> [(b, c)] -> [(a, c)] trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

T ypes: Understanding Code

slide-92
SLIDE 92

trans :: Eq b => [(a, b)] -> [(b, c)] -> [(a, c)] trans xs ys = case xs of [] -> [] ((a,b):xs) -> (map (\(x,y) -> (a,y)) $ f ys) ++ trans xs ys where f [] = [] f ((c,d):ys) | c==b = (b,d) : f ys | otherwise = f ys

T ypes: Understanding Code

slide-93
SLIDE 93

T ypes: Understanding Code

trans :: Eq b => [(a, b)] -> [(b, c)] -> [(a, c)] trans xs ys = [(a,c) | (a,b1) <- xs, (b2,c) <- ys, b1 == b2]

slide-94
SLIDE 94

T ypes: Handling very abstract code

ala :: Newtype srb => (b -> sb) -> ((a -> sb) -> ta -> srb) -> (a -> b) -> (ta -> Unwrap srb) ala w h f = unwrap . h (w . f) What is ‘h’ ?

slide-95
SLIDE 95

T ypes: Handling very abstract code

ala :: Newtype srb => (b -> sb) -> ((a -> sb) -> ta -> srb) -> (a -> b) -> (ta -> Unwrap srb) ala w h f = unwrap . h (w . f)

slide-96
SLIDE 96

T ypes: Handling very abstract code

ala :: Newtype srb => (b -> sb) -> ((a -> sb) -> ta -> srb) -> (a -> b) -> (ta -> Unwrap srb) ala w h f = unwrap . h (w . f)

slide-97
SLIDE 97

T ypes: Side Effects

f :: A -> State s B do y <- chunk1(a,b) z <- chunk1(a,b) chunk3(x) chunk4(y,z)

slide-98
SLIDE 98

T ypes: Side Effects

chunk0 a = do y <- chunk1(a,b) z <- chunk1(a,b) chunk3(x) chunk4(y,z) return z

slide-99
SLIDE 99

T ypes: Side Effects

chunk0 :: A -> State (Int,Bool) Z chunk0 a = do y <- chunk1(a,b) z <- chunk1(a,b) chunk3(x) chunk4(y,z) return z

slide-100
SLIDE 100

T ypes: Side Effects

chunk0 :: Int -> ReaderT Config (StateT Connection (EitherT DBError Int)) chunk0 a = do y <- chunk1(a,b) z <- chunk1(a,b) chunk3(x) chunk4(y,z) return z

slide-101
SLIDE 101

T ype Systems - Benefits

✤ Make code simpler to read ✤ Help locate bugs (in type-correct code !) ✤ Help understand normal code ✤ Help understand very abstract code ✤ Document side-effects ✤ Make code simpler to UNDERSTAND !!!!!!!

slide-102
SLIDE 102

T ype Systems - Pitfalls

slide-103
SLIDE 103

T ype Systems - Pitfalls

✤ Longer to get running code ✤ Changing your mind ✤ Learning Curve - “A Second Language”

slide-104
SLIDE 104

Summary

✤ Functional Programming makes code SIMPLER ✤ PURITY + TYPES are the two biggest ways it does this

slide-105
SLIDE 105

End

Ben Moseley — ben@moseley.name