Introduction to Functional Programming
hello! Jordan Parmer @ProfParmer
What is Functional Programming?
A Very Short Story
“
“We are builders first; technologists second
“The better builders we are, the more value we provide.
1. What is Functional Programming?
What Does It Mean to be Imperative?
What Are The Most Common Problems In Imperative OOP Code?
Null Pointer Exceptions Concurrency Errors With Shared State Broad Context of Reasoning Deep Inheritance Chains Mutable State
What is the emphasis with imperative OOP code?
Inheritance over composition Abstraction by Inheritance Internal class state and encapsulation Imperative state mutations
Can We Do Better?
Return to Roots
“A functional programming language is a language that emphasises programming with pure functions and immutable data
Functional Programming Declarative Describe what, not how Expressions over statements Idempotent Immutability Functions are without side-effects Results deterministic Referentially Transparent Any expression can be replaced with the results of its value Algebraic Types, equality, expressions Category theory Functionally Composable Separate behavior from data Small functions composed together to make small building blocks Parallelizable Idempotent code by nature enables local and distributed parallelization
Myths ✘Requires a math degree to understand ✘Targets only math/science problems ✘Only relevant in academic circles ✘Not for “Line of Business” or “Form Over Data” apps
LIES!
Shocking Adjustments ✘No Null ✘Recursion over looping ✘Avoidance of if-statements ✘Map/filter/fold over iterating ✘Monadic I/O ✘Lots of foreign mathematical nomenclature ✘No debuggers
“OOP makes code understandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts. ✘Michael Feathers
We Want These
You Don’t Need a Functional Language To Be Functional
But It Does Help
Some [Subjective] Examples Pure-ish ✘ Haskell ✘ Erlang ✘ Elm ✘ Hope ✘ Joy ✘ Mercury ✘ Scheme Hybrids ✘ Scala ✘ F# ✘ Kotlin ✘ Swift ✘ ML ✘ LISP ✘ Rust ✘ Groovy ✘ R ✘ Dart ✘ Ruby Progressively Incorporating ✘ Java 8 ✘ C# ✘ Python ✘ C++ 11 ...and many more
Popular Languages Beware Bias Ahead
JVM Languages Scala ✘ Statically strong typed ✘ FP with OOP good parts ✘ Higher-order functions ✘ Insanely advanced type system ✘ Currying, lazy-evaluation, pattern matching, etc. ✘ Large commercial adoption Twitter, Spotify, LinkedIn, Apache Spark, Kafka, etc. ✘ Backed by Lightbend + Scala Centre Clojure ✘ Dynamically typed ✘ First-order functions ✘ S-expressions ✘ LISP-dialect “Modern LISP that is symbiotic with Java”
.NET Languages F# ✘ Statically typed ✘ Multi-paradigm: FP, imperative, OOP ✘ .NET Framework ✘ Visual Studio Tooling ✘ Backed by Microsoft
Apple Languages Swift ✘ Scala...brought to you by Apple I kid! I kid! ✘ FP alternative to Objective C ✘ Borrowed some constructs from C & Objective C ✘ Optional types ✘ Categories (i.e. type-classes)
Erlang Languages Erlang ✘ Ideal for distributed systems ✘ Fault-tolerant, real-time ✘ Highly-available systems ✘ BEAM virtual machine Elixir ✘ Higher abstractions on top of Erlang Reduces boilerplate ✘ Runs on BEAM ✘ New language but closely related to Erlang
Purist Languages Haskell ✘ Purely functional ✘ Named after Haskell Curry ✘ Strong type system ✘ Introduced type-classes ✘ Strict immutability Elm ✘ FP for the web ✘ Graphical layout without destructive updates ✘ Interops with (not compiles to) JavaScript/CSS/HTML
...And So Many More
But What Does That All Mean?
Let’s Talk About Some FP Concepts
The Suspects Pure Functions Expressions Type Systems Function Chaining Map, Filter, Fold Functors, Monoids, Monads
Side-Effects Are The Source of Many Woes
Consider Algebra
f(x) = 3x2-7x+5Given the above Find f(-4)
f(x) = 3x2-7x+5Given the above Find f(-4) 81
Function Has Side-Effects If It... ✘Modifies a variable ✘Modifies a data structure in place e.g. append to linked list ✘Throws an exception ✘Prints to the console ✘Writes to a file ✘Updates a database ✘Draws to the screen
Function Has Side-Effects If It... ✘Modifies a variable ✘Modifies a data structure in place e.g. append to linked list ✘Throws an exception ✘Prints to the console ✘Writes to a file ✘Updates a database ✘Draws to the screen Have you ever passed a reference of a list to something else?
Single Input Single Output No side effects Referentially transparent Func A B Function Is Pure If It...
Why is this Good?
Functional Imperative OOP Pure functions are easy to test Local reasoning In => Out VS Objects are hard to test Encapsulated state Context Global reasoning
Pure functions are easy to re-use Low risk Little-to-no dependencies VS We are terrible at making truly reusable objects Challenges of tight coupling Hard to abstract at correct level Functional Imperative OOP
Pure functions are easy to parallelize State in isolation Just lego pieces VS Sharing is cool in life...not in threads How many concurrency patterns do we need to deal with shared state? Functional Imperative OOP
Pure functions reduce need for most OOP design patterns VS ‘Cause who doesn’t want to know about your MVVMVMVMMVCCC singleton factory observer adapter thingy? Functional Imperative OOP
Function Composition
Single Input Single Output Func A B
Functions Of This Sort Can Be Things Func A B
Functions Of This Sort Can Be Things Func A B
Two Functions Func Func
Compose Them Together Func Func
Compose Them Together Func Func
New Function! Func
Function Composition Is The New Old Injection
// Goal: Allow brewing coffee with different techniques and beans // Types // Beans => Grind // Grind => Coffee Compose to get: Beans => Coffee trait Beans trait Grind trait Coffee case class ColumbianBeans() extends Beans def brew(grind: Beans => Grind)(brew: Grind => Coffee): Beans => Coffee = { brew compose grind } def burrGrind(beans: Beans): Grind = ??? def blendGrind(beans: Beans): Grind = ??? def pourOver(grind: Grind): Coffee = ??? def drip(grind: Grind): Coffee = ??? def frenchPress(grind: Grind): Coffee = ??? val pourOverWithBurrGrind = brew(burrGrind)(pourOver) val myFavoriteBeans = ColumbianBeans() val myFavoriteCoffee = pourOverWithBurrGrind(myFavoriteBeans) // TIME TO WAKE UP!!!
// Goal: Allow brewing coffee with different techniques and beans // Types // Beans => Grind // Grind => Coffee Compose to get: Beans => Coffee trait Beans trait Grind trait Coffee case class ColumbianBeans() extends Beans def brew(grind: Beans => Grind)(brew: Grind => Coffee): Beans => Coffee = { brew compose grind } def burrGrind(beans: Beans): Grind = ??? def blendGrind(beans: Beans): Grind = ??? def pourOver(grind: Grind): Coffee = ??? def drip(grind: Grind): Coffee = ??? def frenchPress(grind: Grind): Coffee = ??? val pourOverWithBurrGrind = brew(burrGrind)(pourOver) val myFavoriteBeans = ColumbianBeans() val myFavoriteCoffee = pourOverWithBurrGrind(myFavoriteBeans) // TIME TO WAKE UP!!! brew is a higher order function
Why Useful?
// Imagine how many combinations we can use this code // Imagine how easy testing is object Person { def drink(coffee: Coffee): AwakePerson = ??? } def wakeSomeone(makeIt: () => Coffee): AwakePerson = { Person.drink(makeIt()) } Anything that makes coffee
Expressions
// Which right triangle that has integers for all sides and all sides equal to // or smaller than 10 has a perimeter of 24? def rightTriangle: Seq[Int] = for { c <- 1 to 10 b <- 1 to c a <- 1 to b if ((Math.pow(a,2) + Math.pow(b,2) == Math.pow(c,2)) && (a + b + c == 24)) } yield (a, b, c) rightTriangle Answer: [6, 8, 10] It’s Not About the How but the What
Type Constraints
f(x) = 3/x Int => Double
f(x) = 3/x 1 => 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ???
f(x) = 3/x 1 => 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ??? AH, PICKLES!
f(x) = 3/x 1 => 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ??? THROW AN EXCEPTION?
f(x) = 3/x Int => Double 0 => 3/0 => ??? THROW AN EXCEPTION? THEN THIS IS A LIE!
f(x) = 3/x Int => Double 0 => 3/0 => ??? THROW AN EXCEPTION? THEN THIS IS A LIE! Are You A Liar?
But Functions Are Types! Types Don’t Have to Be Open to All Circumstances
f(x) = 3/x NonZeroInt => Double Just Became Constrained And Self-Documented
f(x) = 3/x Zero Not Allowed BY NonZeroInt -1 => 3/-1 => -3 1 => 3/1 => 3 2 => 3/2 => 1.5
Static Types Just Became Enforced Domain Documentation
We Sometimes Refer to Our Programs as an “Algebra”
If It Compiles, It Probably Works
Function Chaining
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } }
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Yeah, I know this is bad. But you know you’ve seen this before. Hang with me.
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom The Only Lines Doing Work That’s only 20%!
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Look at all those nulls! Half this code is null checking. Nulls are a serious code smell!
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Look at all those nulls! Half this code is null checking. Nulls are a serious code smell! Null Pointer Exceptions Waiting to Happen
def foo(): Thing = { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Throw in async operations, we can create the same pyramid with nested callbacks.
FP to the Rescue!
def foo(): Option[Int] = { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z }
def foo(): Option[Int] = { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z } Every line is significant
def foo(): Option[Int] = { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z } Every line is significant
Code Examples
Application Becomes a Collection of Pure Functions
Just Fold the Collection
Parallelization Fold All the Pieces!
Monads The Key to a Lot of Awesome
Functors, Monoids, and Bears
Functor A => B
Monoid Type A Identity Function Binary Combinator
Monad Type with a Functor + FlatMap
State
State State stays in box
State The box is a “monad”
State Think of monad as collection of at most one item
State You can do collection things to monads Operation creates new monad of same type but new state .map(...) .flatMap(...) .fold(...) .filter(...) .collect(...) .head
State If Monad is “empty”, applied functions are ignored .map(...) .flatMap(...) .fold(...) .filter(...) .collect(...) .head
def foo(): Option[Int] = Some(100) val myFoo = foo() val result = myFoo .map(i => i + 100) .map(i => i.toString) .map(i => i + " is a bigger number") .getOrElse("didn't do anything") // result = "200 is a bigger number"
def foo(): Option[Int] = None val myFoo = foo() val result = myFoo .map(i => i + 100) .map(i => i.toString) .map(i => i + " is a bigger number") .getOrElse("didn't do anything") // result = "didn’t do anything" Executed but not applied
Monads are so much more but let’s keep it simple for now… ...another talk to come
2. Common Applications
Trends in Functional Programming Data Processing Streaming Parallelization Machine Learning Heavy Computation Attracting Talent
3. Disadvantages?
4. Final Thoughts
Natural way to migrate To Functional Programming?
thanks! Any questions? You can find me at @ProfParmer

Intro to Functional Programming

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
    “We are buildersfirst; technologists second
  • 7.
    “The better builderswe are, the more value we provide.
  • 8.
  • 9.
    What Does ItMean to be Imperative?
  • 10.
    What Are TheMost Common Problems In Imperative OOP Code?
  • 11.
    Null Pointer Exceptions ConcurrencyErrors With Shared State Broad Context of Reasoning Deep Inheritance Chains Mutable State
  • 12.
    What is theemphasis with imperative OOP code?
  • 13.
    Inheritance over composition Abstractionby Inheritance Internal class state and encapsulation Imperative state mutations
  • 14.
    Can We DoBetter?
  • 15.
  • 16.
    “A functional programminglanguage is a language that emphasises programming with pure functions and immutable data
  • 17.
    Functional Programming Declarative Describe what,not how Expressions over statements Idempotent Immutability Functions are without side-effects Results deterministic Referentially Transparent Any expression can be replaced with the results of its value Algebraic Types, equality, expressions Category theory Functionally Composable Separate behavior from data Small functions composed together to make small building blocks Parallelizable Idempotent code by nature enables local and distributed parallelization
  • 18.
    Myths ✘Requires a mathdegree to understand ✘Targets only math/science problems ✘Only relevant in academic circles ✘Not for “Line of Business” or “Form Over Data” apps
  • 19.
  • 20.
    Shocking Adjustments ✘No Null ✘Recursionover looping ✘Avoidance of if-statements ✘Map/filter/fold over iterating ✘Monadic I/O ✘Lots of foreign mathematical nomenclature ✘No debuggers
  • 21.
    “OOP makes codeunderstandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts. ✘Michael Feathers
  • 22.
  • 23.
    You Don’t Needa Functional Language To Be Functional
  • 24.
  • 25.
    Some [Subjective] Examples Pure-ish ✘Haskell ✘ Erlang ✘ Elm ✘ Hope ✘ Joy ✘ Mercury ✘ Scheme Hybrids ✘ Scala ✘ F# ✘ Kotlin ✘ Swift ✘ ML ✘ LISP ✘ Rust ✘ Groovy ✘ R ✘ Dart ✘ Ruby Progressively Incorporating ✘ Java 8 ✘ C# ✘ Python ✘ C++ 11 ...and many more
  • 26.
  • 27.
    JVM Languages Scala ✘ Staticallystrong typed ✘ FP with OOP good parts ✘ Higher-order functions ✘ Insanely advanced type system ✘ Currying, lazy-evaluation, pattern matching, etc. ✘ Large commercial adoption Twitter, Spotify, LinkedIn, Apache Spark, Kafka, etc. ✘ Backed by Lightbend + Scala Centre Clojure ✘ Dynamically typed ✘ First-order functions ✘ S-expressions ✘ LISP-dialect “Modern LISP that is symbiotic with Java”
  • 28.
    .NET Languages F# ✘ Staticallytyped ✘ Multi-paradigm: FP, imperative, OOP ✘ .NET Framework ✘ Visual Studio Tooling ✘ Backed by Microsoft
  • 29.
    Apple Languages Swift ✘ Scala...broughtto you by Apple I kid! I kid! ✘ FP alternative to Objective C ✘ Borrowed some constructs from C & Objective C ✘ Optional types ✘ Categories (i.e. type-classes)
  • 30.
    Erlang Languages Erlang ✘ Idealfor distributed systems ✘ Fault-tolerant, real-time ✘ Highly-available systems ✘ BEAM virtual machine Elixir ✘ Higher abstractions on top of Erlang Reduces boilerplate ✘ Runs on BEAM ✘ New language but closely related to Erlang
  • 31.
    Purist Languages Haskell ✘ Purelyfunctional ✘ Named after Haskell Curry ✘ Strong type system ✘ Introduced type-classes ✘ Strict immutability Elm ✘ FP for the web ✘ Graphical layout without destructive updates ✘ Interops with (not compiles to) JavaScript/CSS/HTML
  • 32.
  • 33.
    But What DoesThat All Mean?
  • 34.
    Let’s Talk AboutSome FP Concepts
  • 35.
    The Suspects Pure Functions Expressions TypeSystems Function Chaining Map, Filter, Fold Functors, Monoids, Monads
  • 36.
  • 37.
  • 38.
    f(x) = 3x2-7x+5Giventhe above Find f(-4)
  • 39.
    f(x) = 3x2-7x+5Giventhe above Find f(-4) 81
  • 40.
    Function Has Side-EffectsIf It... ✘Modifies a variable ✘Modifies a data structure in place e.g. append to linked list ✘Throws an exception ✘Prints to the console ✘Writes to a file ✘Updates a database ✘Draws to the screen
  • 41.
    Function Has Side-EffectsIf It... ✘Modifies a variable ✘Modifies a data structure in place e.g. append to linked list ✘Throws an exception ✘Prints to the console ✘Writes to a file ✘Updates a database ✘Draws to the screen Have you ever passed a reference of a list to something else?
  • 42.
    Single Input Single Output Noside effects Referentially transparent Func A B Function Is Pure If It...
  • 43.
  • 44.
    Functional Imperative OOP Purefunctions are easy to test Local reasoning In => Out VS Objects are hard to test Encapsulated state Context Global reasoning
  • 45.
    Pure functions are easyto re-use Low risk Little-to-no dependencies VS We are terrible at making truly reusable objects Challenges of tight coupling Hard to abstract at correct level Functional Imperative OOP
  • 46.
    Pure functions are easyto parallelize State in isolation Just lego pieces VS Sharing is cool in life...not in threads How many concurrency patterns do we need to deal with shared state? Functional Imperative OOP
  • 47.
    Pure functions reduce needfor most OOP design patterns VS ‘Cause who doesn’t want to know about your MVVMVMVMMVCCC singleton factory observer adapter thingy? Functional Imperative OOP
  • 48.
  • 49.
    Single Input SingleOutput Func A B
  • 50.
    Functions Of ThisSort Can Be Things Func A B
  • 51.
    Functions Of ThisSort Can Be Things Func A B
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
    Function Composition Is TheNew Old Injection
  • 57.
    // Goal: Allowbrewing coffee with different techniques and beans // Types // Beans => Grind // Grind => Coffee Compose to get: Beans => Coffee trait Beans trait Grind trait Coffee case class ColumbianBeans() extends Beans def brew(grind: Beans => Grind)(brew: Grind => Coffee): Beans => Coffee = { brew compose grind } def burrGrind(beans: Beans): Grind = ??? def blendGrind(beans: Beans): Grind = ??? def pourOver(grind: Grind): Coffee = ??? def drip(grind: Grind): Coffee = ??? def frenchPress(grind: Grind): Coffee = ??? val pourOverWithBurrGrind = brew(burrGrind)(pourOver) val myFavoriteBeans = ColumbianBeans() val myFavoriteCoffee = pourOverWithBurrGrind(myFavoriteBeans) // TIME TO WAKE UP!!!
  • 58.
    // Goal: Allowbrewing coffee with different techniques and beans // Types // Beans => Grind // Grind => Coffee Compose to get: Beans => Coffee trait Beans trait Grind trait Coffee case class ColumbianBeans() extends Beans def brew(grind: Beans => Grind)(brew: Grind => Coffee): Beans => Coffee = { brew compose grind } def burrGrind(beans: Beans): Grind = ??? def blendGrind(beans: Beans): Grind = ??? def pourOver(grind: Grind): Coffee = ??? def drip(grind: Grind): Coffee = ??? def frenchPress(grind: Grind): Coffee = ??? val pourOverWithBurrGrind = brew(burrGrind)(pourOver) val myFavoriteBeans = ColumbianBeans() val myFavoriteCoffee = pourOverWithBurrGrind(myFavoriteBeans) // TIME TO WAKE UP!!! brew is a higher order function
  • 59.
  • 60.
    // Imagine howmany combinations we can use this code // Imagine how easy testing is object Person { def drink(coffee: Coffee): AwakePerson = ??? } def wakeSomeone(makeIt: () => Coffee): AwakePerson = { Person.drink(makeIt()) } Anything that makes coffee
  • 61.
  • 62.
    // Which righttriangle that has integers for all sides and all sides equal to // or smaller than 10 has a perimeter of 24? def rightTriangle: Seq[Int] = for { c <- 1 to 10 b <- 1 to c a <- 1 to b if ((Math.pow(a,2) + Math.pow(b,2) == Math.pow(c,2)) && (a + b + c == 24)) } yield (a, b, c) rightTriangle Answer: [6, 8, 10] It’s Not About the How but the What
  • 63.
  • 64.
    f(x) = 3/x Int=> Double
  • 65.
    f(x) = 3/x 1=> 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ???
  • 66.
    f(x) = 3/x 1=> 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ??? AH, PICKLES!
  • 67.
    f(x) = 3/x 1=> 3/1 => 3.0 2 => 3/2 => 1.5 0 => 3/0 => ??? THROW AN EXCEPTION?
  • 68.
    f(x) = 3/x Int=> Double 0 => 3/0 => ??? THROW AN EXCEPTION? THEN THIS IS A LIE!
  • 69.
    f(x) = 3/x Int=> Double 0 => 3/0 => ??? THROW AN EXCEPTION? THEN THIS IS A LIE! Are You A Liar?
  • 70.
    But Functions AreTypes! Types Don’t Have to Be Open to All Circumstances
  • 71.
    f(x) = 3/x NonZeroInt=> Double Just Became Constrained And Self-Documented
  • 72.
    f(x) = 3/x ZeroNot Allowed BY NonZeroInt -1 => 3/-1 => -3 1 => 3/1 => 3 2 => 3/2 => 1.5
  • 73.
    Static Types JustBecame Enforced Domain Documentation
  • 75.
    We Sometimes Referto Our Programs as an “Algebra”
  • 76.
    If It Compiles,It Probably Works
  • 77.
  • 78.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } }
  • 79.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Yeah, I know this is bad. But you know you’ve seen this before. Hang with me.
  • 80.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom
  • 81.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom The Only Lines Doing Work That’s only 20%!
  • 82.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Look at all those nulls! Half this code is null checking. Nulls are a serious code smell!
  • 83.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Look at all those nulls! Half this code is null checking. Nulls are a serious code smell! Null Pointer Exceptions Waiting to Happen
  • 84.
    def foo(): Thing= { val x = DoAThing() if (x != null) { val y = DoAnotherThing(x) if (y != null) { val z = DoYetAnotherThing(y) if (z != null) { return z } else { return null } } else { return null } } else { return null } } Pyramid of Doom Throw in async operations, we can create the same pyramid with nested callbacks.
  • 85.
    FP to theRescue!
  • 86.
    def foo(): Option[Int]= { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z }
  • 87.
    def foo(): Option[Int]= { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z } Every line is significant
  • 88.
    def foo(): Option[Int]= { for { x <- DoAThing() y <- DoAnotherThing(x) z <- DoYetAnotherThing(y) } yield z } Every line is significant
  • 89.
  • 90.
  • 91.
    Just Fold theCollection
  • 92.
  • 94.
    Monads The Key toa Lot of Awesome
  • 95.
  • 96.
  • 97.
  • 98.
    Monad Type with aFunctor + FlatMap
  • 99.
  • 100.
  • 101.
    State The box isa “monad”
  • 102.
  • 103.
    State You can docollection things to monads Operation creates new monad of same type but new state .map(...) .flatMap(...) .fold(...) .filter(...) .collect(...) .head
  • 104.
    State If Monad is“empty”, applied functions are ignored .map(...) .flatMap(...) .fold(...) .filter(...) .collect(...) .head
  • 105.
    def foo(): Option[Int]= Some(100) val myFoo = foo() val result = myFoo .map(i => i + 100) .map(i => i.toString) .map(i => i + " is a bigger number") .getOrElse("didn't do anything") // result = "200 is a bigger number"
  • 106.
    def foo(): Option[Int]= None val myFoo = foo() val result = myFoo .map(i => i + 100) .map(i => i.toString) .map(i => i + " is a bigger number") .getOrElse("didn't do anything") // result = "didn’t do anything" Executed but not applied
  • 107.
    Monads are somuch more but let’s keep it simple for now… ...another talk to come
  • 108.
  • 109.
    Trends in FunctionalProgramming Data Processing Streaming Parallelization Machine Learning Heavy Computation Attracting Talent
  • 110.
  • 112.
  • 113.
    Natural way tomigrate To Functional Programming?
  • 114.
    thanks! Any questions? You canfind me at @ProfParmer

Editor's Notes

  • #3 Good morning. My name is Jordan. I’m a software engineer for a company in OKC called “Oseberg” where I lead the Data Platform team. We use a lot of FP at Oseberg. In fact, all of our server-side code is FP using a language called Scala. How many of you have used functional programming professionally? As a hobby? A strict functional programming language?
  • #4 Get a raise of hands for who has done functional programming before.
  • #5 Describe the paradigm phases over the years (procedural => oop => functional) Fascination of video games as child (not necessarily gaming itself but the building aspect) Story of dad buying my first programming book (show next slide with QBasic book)
  • #6 I read this book cover-to-cover. Was fascinated. Felt like I knew a secret code or language that few others knew. I think that is a feeling many of us in this room probably felt at one time or another. The love of the tinkering. The love of the hacking around. The love of building something out of logic. Infinite loops, beeping ASCII codes, etc.
  • #7 When we first learn programming, we are concerned about syntax. How do I enter the correct codes, symbols, and keywords to appease the wrath of the compiler and have our little code run? Next, we are concerned with how to model things. What is the best way to represent this logical concept in the real world? Next, how do we have our models interact with each other? Next, how do we work in a team with other people writing code? Next, how do we have systems talk to each other? … The further we go, the more evolved the problems we are solving. In today’s world, we now find ourselves processing Big Data. Massive volumes of data, many CPU cores, distributed computing clusters, and a high degree of parallelism. The problems we are solving today are not the problems we were solving yesterday.
  • #8 That is why our field is about the pursuit of building. We are builders first and technologists second. How do we build things? And this means we should always be learning how to build in new ways.
  • #10 Ask the audience.
  • #11 Ask the audience.
  • #13 Ask the audience.
  • #20 Now this doesn’t mean we don’t have to learn new terminology. When we learned algebra, we could no longer constrain ourselves to basic addition and subtraction. Had to learn new phrases. When we learned OOP, we had to learn about classes, objects, encapsulation, inheritance, etc. New lingo for different techniques. Same with FP. You are going to have to learn about referential integrity, functors, monoids, monads, typeclasses, etc.
  • #39 What if in algebra class your teacher docked you points because in reality, usage of ‘x’ mutated its state so that it wasn’t constant within the use of the function f() and the answer changes? You’d cry fowl! But don’t we do this kind of stuff all the time? When we were first becoming programmers, this is the kind of habits we were taught. Changing state.
  • #40 What if in algebra class your teacher docked you points because in reality, usage of ‘x’ mutated its state so that it wasn’t constant within the use of the function f() and the answer changes? You’d cry fowl! But don’t we do this kind of stuff all the time? When we were first becoming programmers, this is the kind of habits we were taught. Changing state.
  • #65 Will this work for all inputs? How might we code this up?
  • #66 Will this work for all inputs? How might we code this up?
  • #67 Will this work for all inputs? How might we code this up?
  • #68 Will this work for all inputs? How might we code this up?
  • #69 Will this work for all inputs? How might we code this up?
  • #70 Will this work for all inputs? How might we code this up?
  • #72 Will this work for all inputs? How might we code this up?
  • #73 Will this work for all inputs? How might we code this up?