Slide 1

Slide 1 text

Brendan McAdams 10gen, Inc. [email protected] @rit “Functions All The Way Down” A (Somewhat Gentle) Introduction to Functional Programming

Slide 2

Slide 2 text

Everything That’s Old Is New Again...

Slide 3

Slide 3 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept

Slide 4

Slide 4 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept • Rooted in the concepts of Lambda Calculus (~1930s)

Slide 5

Slide 5 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept • Rooted in the concepts of Lambda Calculus (~1930s) • Introduced in many early languages such as Lisp

Slide 6

Slide 6 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept • Rooted in the concepts of Lambda Calculus (~1930s) • Introduced in many early languages such as Lisp • Recently undergoing a renaissance

Slide 7

Slide 7 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept • Rooted in the concepts of Lambda Calculus (~1930s) • Introduced in many early languages such as Lisp • Recently undergoing a renaissance • Functional Languages like Haskell, Clojure and Scala gaining popularity as “real” tools

Slide 8

Slide 8 text

Everything That’s Old Is New Again... • Functional Programming is far from a new concept • Rooted in the concepts of Lambda Calculus (~1930s) • Introduced in many early languages such as Lisp • Recently undergoing a renaissance • Functional Languages like Haskell, Clojure and Scala gaining popularity as “real” tools • Traditionally imperative languages such as C++ are gaining concepts from functional languages in recent revisions

Slide 9

Slide 9 text

Everything That’s Old Is New Again...

Slide 10

Slide 10 text

Everything That’s Old Is New Again... • We improve ourselves and our code by learning from & leveraging FP

Slide 11

Slide 11 text

Everything That’s Old Is New Again... • We improve ourselves and our code by learning from & leveraging FP • Avoiding Mutable values and State for referential transparency

Slide 12

Slide 12 text

Everything That’s Old Is New Again... • We improve ourselves and our code by learning from & leveraging FP • Avoiding Mutable values and State for referential transparency • Using functions as a higher level concept for composition

Slide 13

Slide 13 text

Everything That’s Old Is New Again... • We improve ourselves and our code by learning from & leveraging FP • Avoiding Mutable values and State for referential transparency • Using functions as a higher level concept for composition • ... and thinking in terms of functions being closer to the composable, reusable units they are meant to be

Slide 14

Slide 14 text

Everything That’s Old Is New Again...

Slide 15

Slide 15 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala)

Slide 16

Slide 16 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala) • This is by no means a comprehensive course on functional programming

Slide 17

Slide 17 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala) • This is by no means a comprehensive course on functional programming • If you like what you see, I recommend a few books

Slide 18

Slide 18 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala) • This is by no means a comprehensive course on functional programming • If you like what you see, I recommend a few books • “Learn You A Haskell For Great Good” (Lightweight & lighthearted)

Slide 19

Slide 19 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala) • This is by no means a comprehensive course on functional programming • If you like what you see, I recommend a few books • “Learn You A Haskell For Great Good” (Lightweight & lighthearted) • “The Little Schemer” (if you like Lisp)

Slide 20

Slide 20 text

Everything That’s Old Is New Again... • I am going to introduce some functional programming (as well as a little bit of my favorite language for it, Scala) • This is by no means a comprehensive course on functional programming • If you like what you see, I recommend a few books • “Learn You A Haskell For Great Good” (Lightweight & lighthearted) • “The Little Schemer” (if you like Lisp) • “Real World Haskell” (heavy and in depth, if you want a real dive)

Slide 21

Slide 21 text

What is this? int multiply(int x, int y) { return x * y; }

Slide 22

Slide 22 text

What is this? int multiply(int x, int y) { return x * y; } That’s right... it’s a function (in C/C++)

Slide 23

Slide 23 text

What is this? int multiply(int x, int y) { return x * y; } That’s right... it’s a function (in C/C++) We can invoke it to calculate a value...

Slide 24

Slide 24 text

What is this? int multiply(int x, int y) { return x * y; } That’s right... it’s a function (in C/C++) We can invoke it to calculate a value... int main() { int x = 512000; int y = 128; int z = multiply(x, y); std::cout << x << "*" << y << " is: " << z << std::endl; }

Slide 25

Slide 25 text

Python shouldn’t be too different... def multiply(x, y): return x * y if __name__ == '__main__': x = 512000 y = 128 z = multiply(x, y) print "%i*%i is %i" % (x, y, z)

Slide 26

Slide 26 text

Python shouldn’t be too different... def multiply(x, y): return x * y if __name__ == '__main__': x = 512000 y = 128 z = multiply(x, y) print "%i*%i is %i" % (x, y, z) Python has some FP influence though...

Slide 27

Slide 27 text

Python shouldn’t be too different... def multiply(x, y): return x * y if __name__ == '__main__': x = 512000 y = 128 z = multiply(x, y) print "%i*%i is %i" % (x, y, z) Python has some FP influence though... print "Multiply Function: %s" % multiply # Multiply Function: foobar = multiply print "%i*%i is %i" % (x, y, foobar(x, y))

Slide 28

Slide 28 text

First Class Functions

Slide 29

Slide 29 text

First Class Functions • These tricks work because Python considers functions to be “first class”

Slide 30

Slide 30 text

First Class Functions • These tricks work because Python considers functions to be “first class” • a function named “multiply” is simply a variable of type “function”

Slide 31

Slide 31 text

First Class Functions • These tricks work because Python considers functions to be “first class” • a function named “multiply” is simply a variable of type “function” • Technically you can use pointers to do similar tricks in C/C++ but it’s far from easy (or transparent)

Slide 32

Slide 32 text

First Class Functions • These tricks work because Python considers functions to be “first class” • a function named “multiply” is simply a variable of type “function” • Technically you can use pointers to do similar tricks in C/C++ but it’s far from easy (or transparent) • Many languages segregate function as if they are special, meaning they are not truly composable units of work.

Slide 33

Slide 33 text

First Class Functions • These tricks work because Python considers functions to be “first class” • a function named “multiply” is simply a variable of type “function” • Technically you can use pointers to do similar tricks in C/C++ but it’s far from easy (or transparent) • Many languages segregate function as if they are special, meaning they are not truly composable units of work. • In FP, we try to leverage the function as just another tool - meaning it must be flexible, reusable and first class.

Slide 34

Slide 34 text

Let’s Look at Scala

Slide 35

Slide 35 text

Let’s Look at Scala • Python is not truly functional, but instead borrows some concepts of functional programming

Slide 36

Slide 36 text

Let’s Look at Scala • Python is not truly functional, but instead borrows some concepts of functional programming • Instead, let’s look at Scala... which is a true blend of Object Oriented + Functional programming with a full arsenal of FP tools.

Slide 37

Slide 37 text

Let’s Look at Scala • Python is not truly functional, but instead borrows some concepts of functional programming • Instead, let’s look at Scala... which is a true blend of Object Oriented + Functional programming with a full arsenal of FP tools. • Scala was created by Martin Odersky (author of Java Generics & the 1.5+ javac) at EPFL in Switzlerand

Slide 38

Slide 38 text

Let’s Look at Scala • Python is not truly functional, but instead borrows some concepts of functional programming • Instead, let’s look at Scala... which is a true blend of Object Oriented + Functional programming with a full arsenal of FP tools. • Scala was created by Martin Odersky (author of Java Generics & the 1.5+ javac) at EPFL in Switzlerand • JVM based, able to interoperate cleanly with Java & existing libraries

Slide 39

Slide 39 text

Let’s Look at Scala • Python is not truly functional, but instead borrows some concepts of functional programming • Instead, let’s look at Scala... which is a true blend of Object Oriented + Functional programming with a full arsenal of FP tools. • Scala was created by Martin Odersky (author of Java Generics & the 1.5+ javac) at EPFL in Switzlerand • JVM based, able to interoperate cleanly with Java & existing libraries • Used by companies such as Twitter, Foursquare, The Guardian, LinkedIn, and many more

Slide 40

Slide 40 text

First Class Functions in Scala def multiply(x: Int, y: Int) = { x * y } val n = 512000 val o = 128 val p = multiply(n, o) println("%s*%s is %s".format(n, o, p)) // 512000*128 is 65536000 println("Multiply Function: %s".format(multiply _)) val foobar = multiply _ // Multiply Function: println("%s*%s is %s".format(n, o, foobar(n, o))) // 512000*128 is 65536000

Slide 41

Slide 41 text

Going Anonymous

Slide 42

Slide 42 text

Going Anonymous • If a function is a truly composable & reusable unit, we should also be able to define it ‘anonymously’

Slide 43

Slide 43 text

Going Anonymous • If a function is a truly composable & reusable unit, we should also be able to define it ‘anonymously’ • This concept is sometimes referred to as lambdas

Slide 44

Slide 44 text

Going Anonymous • If a function is a truly composable & reusable unit, we should also be able to define it ‘anonymously’ • This concept is sometimes referred to as lambdas • Lambdas are one of the most borrowed FP concepts in traditional languages

Slide 45

Slide 45 text

Going Anonymous • If a function is a truly composable & reusable unit, we should also be able to define it ‘anonymously’ • This concept is sometimes referred to as lambdas • Lambdas are one of the most borrowed FP concepts in traditional languages • In some cases, Lambdas exist exclusively of “first class” functions (but can be used to tackle similar needs)

Slide 46

Slide 46 text

Anonymous Functions / Lambdas In Scala val multiply = (x: Int, y: Int) => { x * y } val n = 512000 val o = 128 val p = multiply(n, o) println("%s*%s is %s".format(n, o, p)) // 512000*128 is 65536000

Slide 47

Slide 47 text

Anonymous Functions in Other Languages

Slide 48

Slide 48 text

Anonymous Functions in Other Languages • Python has Lambdas as well (but restricts to one liners)

Slide 49

Slide 49 text

Anonymous Functions in Other Languages • Python has Lambdas as well (but restricts to one liners) lambda x, y: x * y # at 0x10acce938> multiply = lambda x, y: x * y multiply(5, 2) # 10

Slide 50

Slide 50 text

Anonymous Functions in Other Languages • Python has Lambdas as well (but restricts to one liners) • C++ 11 is even adding them to C++! lambda x, y: x * y # at 0x10acce938> multiply = lambda x, y: x * y multiply(5, 2) # 10

Slide 51

Slide 51 text

Anonymous Functions in Other Languages • Python has Lambdas as well (but restricts to one liners) • C++ 11 is even adding them to C++! lambda x, y: x * y # at 0x10acce938> multiply = lambda x, y: x * y multiply(5, 2) # 10 [](int x, int y) { return x * y; }

Slide 52

Slide 52 text

Tricks with Functions

Slide 53

Slide 53 text

Tricks with Functions • Let’s look at some tricks used with functions when we have access to them as a proper value

Slide 54

Slide 54 text

Tricks with Functions • Let’s look at some tricks used with functions when we have access to them as a proper value • Higher Order Functions

Slide 55

Slide 55 text

Tricks with Functions • Let’s look at some tricks used with functions when we have access to them as a proper value • Higher Order Functions • Partial Application

Slide 56

Slide 56 text

Tricks with Functions • Let’s look at some tricks used with functions when we have access to them as a proper value • Higher Order Functions • Partial Application • Multiple Argument Lists

Slide 57

Slide 57 text

Tricks with Functions • Let’s look at some tricks used with functions when we have access to them as a proper value • Higher Order Functions • Partial Application • Multiple Argument Lists • Currying

Slide 58

Slide 58 text

Higher Order Functions

Slide 59

Slide 59 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming

Slide 60

Slide 60 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming • The idea is to truly take advantage of functions as values

Slide 61

Slide 61 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming • The idea is to truly take advantage of functions as values • A Higher Order Function either ...

Slide 62

Slide 62 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming • The idea is to truly take advantage of functions as values • A Higher Order Function either ... • Accepts one or more functions as “input”

Slide 63

Slide 63 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming • The idea is to truly take advantage of functions as values • A Higher Order Function either ... • Accepts one or more functions as “input” • Produces a function as its result (“output”)

Slide 64

Slide 64 text

Higher Order Functions • Higher Order functions are one of the most leveraged patterns in functional programming • The idea is to truly take advantage of functions as values • A Higher Order Function either ... • Accepts one or more functions as “input” • Produces a function as its result (“output”) • Or, technically... both!

Slide 65

Slide 65 text

Higher Order Functions def math(x: Int, y: Int, op: (Int, Int) => Int) = { op(x, y) } val multiply = (x: Int, y: Int) => { x * y } val add = (x: Int, y: Int) => { x + y } val sub = (x: Int, y: Int) => { x - y } val divide = (x: Int, y: Int) => { x / y } println(math(10, 5, divide)) // 2 println(math(10, 5, multiply)) // 50 println(math(10, 5, add)) // 15 println(math(10, 5, sub)) // 5

Slide 66

Slide 66 text

Patterns around Higher Order Functions

Slide 67

Slide 67 text

Patterns around Higher Order Functions • There are any number of patterns we can leverage Higher Order Functions in...

Slide 68

Slide 68 text

Patterns around Higher Order Functions • There are any number of patterns we can leverage Higher Order Functions in... • Let’s talk about 2

Slide 69

Slide 69 text

Patterns around Higher Order Functions • There are any number of patterns we can leverage Higher Order Functions in... • Let’s talk about 2 • “Execute Around” / “Loan” Patterns

Slide 70

Slide 70 text

Patterns around Higher Order Functions • There are any number of patterns we can leverage Higher Order Functions in... • Let’s talk about 2 • “Execute Around” / “Loan” Patterns • Inline Manipulation (“map”, “flatMap”, “filter”, etc)

Slide 71

Slide 71 text

Executing Around / Loaning a Resource val file = scala.io.Source("anon.scala") for (line <- file) { println(line) } // ... we forgot to close the file

Slide 72

Slide 72 text

Executing Around / Loaning a Resource def iterateFile(file: String, op: Iterator[String] => Unit) = { val fh = scala.io.Source.fromFile(file) op(fh.getLines) // CLOSE IT! fh.close() } iterateFile("anon.scala", { file => for (line <- file) println(file) })

Slide 73

Slide 73 text

Why “Execute Around”? • Enforces encapsulation and value “leakage”/”exposure” • User gets limited (as in you control the view of the resource) access to some resource (often IO based) • Much easier to handle cleanup, restrict access to certain values/params and “hide implementation”

Slide 74

Slide 74 text

Manipulating Data ... Inline! val fh = scala.io.Source.fromFile("anon.scala") fh.getLines.foreach( line => println(line) ) // Even simpler... implicit... fh.getLines.foreach(println) // Filter out blank lines val isBlank = (x: String) => x == "" val noBlank = fh.getLines.filterNot(isBlank) val blankOnly = fh.getLines.filter(isBlank) // Manipulate on the fly, producing a new datasource val commented = fh.getLines.map{ l => "//%s".format(l) }

Slide 75

Slide 75 text

Why Manipulate Inline?

Slide 76

Slide 76 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play...

Slide 77

Slide 77 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure”

Slide 78

Slide 78 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure” • Limits access to the “core resource”

Slide 79

Slide 79 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure” • Limits access to the “core resource” • More importantly, allows us to more safely control two incredibly important concepts:

Slide 80

Slide 80 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure” • Limits access to the “core resource” • More importantly, allows us to more safely control two incredibly important concepts: • State

Slide 81

Slide 81 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure” • Limits access to the “core resource” • More importantly, allows us to more safely control two incredibly important concepts: • State • Mutability

Slide 82

Slide 82 text

Why Manipulate Inline? • Similar reasons to “Execute Around” come into play... • Enforces encapsulation and value “leakage”/”exposure” • Limits access to the “core resource” • More importantly, allows us to more safely control two incredibly important concepts: • State • Mutability • ... which we’ll elaborate on shortly.

Slide 83

Slide 83 text

Partially Applied Functions • Taking advantage of this “reusable, composable value” concept ... • We can fill in some of the required arguments to a function, and then hand a “partially applied” view to someone else to finish

Slide 84

Slide 84 text

Partially Applied Functions def multiply(x: Int, y: Int) = { x * y } // multiply: (x: Int, y: Int)Int /* multiply(50, 1) Int = 50 */ def squared = multiply(_: Int, 2) // squared: Int => Int /* squared(50) Int = 100 */ def cubed = multiply(_: Int, 3) /* cubed(50) Int = 150 */

Slide 85

Slide 85 text

Accepting Multiple Arguments • Sometimes, there’s some composable beauty in taking multiple argument lists instead of one • Many functional languages allow this (as well as tricks around them) • Think about how we can clean up our multiply function based on the tricks we just pulled with partial application

Slide 86

Slide 86 text

Accepting Multiple Arguments def multiply(multiplier: Int)(value: Int) = { value * multiplier } // multiply: (multiplier: Int)(value: Int)Int /* multiply(1)(50) Int = 50 */

Slide 87

Slide 87 text

Currying Favor • With “Currying” we can leverage multiple argument lists (technically, to “curry” they must each take a single argument) partially applied • This gives us a chain of callable functions • With partial application, we can “lazily” evaluate this chain

Slide 88

Slide 88 text

Currying Favor def squared = multiply(2) _ // squared: Int => Int /* squared(50) Int = 100 */ def cubed = multiply(3) _ // cubed: Int => Int /* cubed(50) Int = 150 */

Slide 89

Slide 89 text

Higher Order Functions + Multiple Args • What I think of as the “beauty” of currying can also be used to clean up things like a “loan” method which takes initialization params • Separate out our function arg from our non-function args ...

Slide 90

Slide 90 text

Higher Order Functions + Multiple Args def math(x: Int, y: Int)(op: (Int, Int) => Int) = { op(x, y) } val multiply = math(10, 5) { (x, y) => x * y } val add = math(10, 5) { (x, y) => x + y } val sub = math(10, 5) { (x, y) => x - y } val divide = math(10, 5) { (x, y) => x / y } println(divide) // 2 println(multiply) // 50 println(add) // 15 println(sub) // 5

Slide 91

Slide 91 text

Higher Order Functions + Multiple Args def iterateFile(file: String)(op: Iterator[String] => Unit) = { val fh = scala.io.Source.fromFile(file) op(fh.getLines) // CLOSE IT! fh.close() } iterateFile("anon.scala") { file => for (line <- file) println(file) }

Slide 92

Slide 92 text

Lazy Values & Memoization

Slide 93

Slide 93 text

Mutability (and how to avoid it)

Slide 94

Slide 94 text

Controlling State