LEARNING FUNCTIONALPROGRAMMING   WITHOUT GROWING A  NECKBEARD   by Kelsey Innis / @kelseyinnis
HI!                    Im Kelsey.I work at StackMob writing code that lets our users create & manage their applications, A...
WHY ARE YOU HERE?http://www.youtube.com/embed/Lb8BCl6NKn0To learn to write code with drive that dont take no              ...
THE PAM GRIER CRITERIA FOR     CODE BADASSERY   Code, like Pam Grier, should be:          Powerful,          Beautiful, an...
POWERFULDo big thingsDo them easilyDo them quickly
TOUGH TO MESS WITHSecure from outside manipulationHard to unintentionally make mistakesEasy to maintain
BEAUTIFULElegant, concise, and--yes--readableAble to be easily reusedFun to write
SCALA!dont need parentheses for method callssemicolons are optionalreturn value is the last line of the methodstatic typin...
BUT WHAT DOES IT LOOK LIKE?val   x: String = "a"val   y = 2val   z = 15.3val   myThing = new Thingval   theList = List("th...
BUT WHAT DOES IT LOOK LIKE?def haggle(theirPrice: Int, myOffer: Int): String = {        val theResponse: String =         ...
FUNCTIONALPROGRAMMING
WHAT IS FUNCTIONAL  PROGRAMMING?  Well, what is a program?
ASK A KID (OR SIMPLE ENGLISH WIKIPEDIA)                 A computer               program is a listWRONG                of ...
Imperative programming:a sequence of commands that the computer carries                 out in sequence          Object-or...
If a programs not a series of commands, then                  what is it?
“Functional programming is a style of programming that emphasizes theevaluation of expressions rather than    the executio...
WHAT THINGS AREval theQueen = "Elizabeth II"                          but also...def theGovernor(state: State) = {        ...
WHAT IS A FUNCTION?          A function is a relation          between values where          each of its input values     ...
SOME FUNCTIONSMath.sqrt(x)Collections.max(list)Arrays.copyOf(original, newLength)String.valueOf(anInt)
A function is pure if “the impact of a function on therest of the program [can] be described only in terms of   its return...
This is our building block.          Sooooo....
FUNCTIONS ARE DETERMINISTIC.You will always get the same result if you run them                with the same data.        ...
FUNCTIONS ARE ENCAPSULATED.“With a referentially transparent function, the interface-     level activity is all one needs ...
FUNCTIONS ARE COMMUTATIVE.val firstThing = doOneThing()val secondThing = doAnotherThing()val thirdThing = doTheLastThing(f...
DATA IS IMMUTABLE.Once an object is created, it cannot be changed.If you need to change an object, make your own          ...
Functions are deterministicFunctions are encapsulatedFunctions are commutativeData is immutable                           ...
...how?
FUNCTIONS AS FIRST CLASS CITIZENS
FIRST CLASS CITIZENSval longSkinnyThing: String = "this is a string"val listOfThem: List[String] = List("yarn","twine","th...
val addSpam: (String) => String =        { (x:String) => x + " and Spam" }addSpam("Egg and Bacon")        //result: "Egg a...
RETURNING FUNCTIONS FROM             FUNCTIONSdef tagText(tag: String, text: String) = "<" + tag +">" + text +""val noReal...
CURRYING  YUM!
HIGHER-ORDER FUNCTIONS
FOR LOOP                               Javapublic void talkAboutFruit {         Fruit[] fruits = {                 new Fru...
LETS GET ABSTRACT    a function that takes a list and a function          (list of parameters types) => return type  forea...
MORE ABSTRACTERER!foreach(theList:List(A), theFunction:         (A) => Unit): Unitabstract class Collection[A] {        .....
THIS:abstract class Collection[A] {        ...        def foreach(theFunction: (A) => Unit): Unit = {                for (...
SOMETHING A LITTLE JUICIERdef makePies: List[Pie] = {        val fruits = List(new Fruit("apple"),                        ...
ANONYMOUS FUNCTIONSval kindOfFruit: String = "blueberry"val blueberryFruit = new Fruit(kindOfFruit)val alsoBlueberry = new...
COLLECTION HANDLING                            FILTERval theList = List(new Fruit("apple"), new Fruit("pear"), new Fruit("...
NESTED FOR-LOOPS  def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):List(Serving[Pie, IceCream]) {         va...
IS THIS AN IMPROVEMENT?def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]): List(Serving[Pie, IceCream]) {     ...
FUNCTION COMPOSITION  def bakeAPie(f: Fruit, c: Crust): Pie  def eatAPie(p: Pie): HappyKelsey  def bakeAndEatAPie(f: Fruit...
FOR-YIELD  def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):List(Serving[Pie, IceCream]) {         for {    ...
FUN WITH FOR-YIELD  def goodPairings(pies: List[Pie], iceCreams: List[IceCream]): List(Serving[Pie, IceCream]) {         f...
partial applicationhigher order functionsfunction compositionfor-yield
AND NOW FOR SOMETHING(NOT REALLY) COMPLETELY DIFFERENT
NULL.
YUCK public Serving<Pie, IceCream> serveBestALaMode(Pie key, Map<Pie, IceCream> pairings) {     if(pairings != null) {    ...
OPTIONOption[T] is either a Some with a value of type T     inside, or None representing nothing. val someOption: Option[S...
def serveBestALaMode(key: Pie, pairings: Map[Pie, IceCream]): Option[Serving[Pie,IceCream]] = {         iceCream: Option[I...
OPTION IS KIND OF LIKE A          COLLECTION                             .MAPsomeOption.map( {(str:String) => str + " SAN ...
FOR-YIELD OVER OPTION for {         pie <- todaysSpecial         bestIceCream <- pairings.get(pie)         iceCream <- ava...
OPTION IS A MONAD   WHAT IS A MONAD?
"Let’s look at what it is that makes Thing a monad.The first thing is that I can wrap up a value inside of anew Thing...We...
FLATMAP IS MAGIC flatMap hides our boilerplate. For Lists, it abstractsaway a for-loop, letting us create a new List from ...
OTHER MONADSaccumulating errorsa cursor position in a database or filestates in a state machinean environment that changes...
EXTRA CREDIT WHOAA SEMICOLON IS A MONAD
partial applicationhigher order functionsfunction compositionfor-yieldmonads
THE PSYCHOLOGY OFFUNCTIONAL PROGRAMMING
READABILITY“Is Clojure code hard to understand? Imagine if every   time you read Java source code and encountered   syntax...
DSLSclass HelloWorldSpec extends Specification {      "The Hello world string" should {        "contain 11 characters" in ...
PURITY“The truth is that good programmers mix the styles quite   a bit. We program imperatively when needed, and   functio...
THANK YOU
Learning Functional Programming Without Growing a Neckbeard
Upcoming SlideShare
Loading in …5
×

Learning Functional Programming Without Growing a Neckbeard

21,683 views

Published on

Slides from 12/13/12 presentation to SF Scala. Video: https://marakana.com/s/post/1354/learning_functional_programming_scala_video

Published in: Technology
0 Comments
27 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
21,683
On SlideShare
0
From Embeds
0
Number of Embeds
7,994
Actions
Shares
0
Downloads
0
Comments
0
Likes
27
Embeds 0
No embeds

No notes for slide

Learning Functional Programming Without Growing a Neckbeard

  1. LEARNING FUNCTIONALPROGRAMMING WITHOUT GROWING A NECKBEARD by Kelsey Innis / @kelseyinnis
  2. HI! Im Kelsey.I work at StackMob writing code that lets our users create & manage their applications, APIs, and data through the browser. I use Scala and the Lift web framework to do that.
  3. WHY ARE YOU HERE?http://www.youtube.com/embed/Lb8BCl6NKn0To learn to write code with drive that dont take no jive.
  4. THE PAM GRIER CRITERIA FOR CODE BADASSERY Code, like Pam Grier, should be: Powerful, Beautiful, and Tough to mess with.
  5. POWERFULDo big thingsDo them easilyDo them quickly
  6. TOUGH TO MESS WITHSecure from outside manipulationHard to unintentionally make mistakesEasy to maintain
  7. BEAUTIFULElegant, concise, and--yes--readableAble to be easily reusedFun to write
  8. SCALA!dont need parentheses for method callssemicolons are optionalreturn value is the last line of the methodstatic typing with type inference
  9. BUT WHAT DOES IT LOOK LIKE?val x: String = "a"val y = 2val z = 15.3val myThing = new Thingval theList = List("this", "sure", "is", "a", "list")val whatIsIt = theList(4)
  10. BUT WHAT DOES IT LOOK LIKE?def haggle(theirPrice: Int, myOffer: Int): String = { val theResponse: String = if (theirPrice <= myOffer + 5) { "Youve got a deal!" } else { "I definitely wouldnt pay more than " + (myOffer + (theirPrice - myOffer)/2) + " for it." } theResponse}val askingPrice = 100val iWantToPay = 50val letsMakeADeal = haggle(askingPrice, iWantToPay)
  11. FUNCTIONALPROGRAMMING
  12. WHAT IS FUNCTIONAL PROGRAMMING? Well, what is a program?
  13. ASK A KID (OR SIMPLE ENGLISH WIKIPEDIA) A computer program is a listWRONG of instructions that tell a computer what to do.
  14. Imperative programming:a sequence of commands that the computer carries out in sequence Object-oriented programming:these instructions, and the data they manipulate, are organized into objects
  15. If a programs not a series of commands, then what is it?
  16. “Functional programming is a style of programming that emphasizes theevaluation of expressions rather than the execution of commands.” —comp.lang.functional FAQ
  17. WHAT THINGS AREval theQueen = "Elizabeth II" but also...def theGovernor(state: State) = { val candidates = state.getCandidates candidates(getTopVoteGetter)}
  18. WHAT IS A FUNCTION? A function is a relation between values where each of its input values gives back exactly one output value, playa.
  19. SOME FUNCTIONSMath.sqrt(x)Collections.max(list)Arrays.copyOf(original, newLength)String.valueOf(anInt)
  20. A function is pure if “the impact of a function on therest of the program [can] be described only in terms of its return type, and...the impact of the rest of theprogram on the function be described only in terms of its arguments”. (Victor Nicollet)
  21. This is our building block. Sooooo....
  22. FUNCTIONS ARE DETERMINISTIC.You will always get the same result if you run them with the same data. correctness is more clear unit tests are a breeze debugging is more directed tough to mess with
  23. FUNCTIONS ARE ENCAPSULATED.“With a referentially transparent function, the interface- level activity is all one needs to know about its behavior.”. (Michael O. Church) readability reuse maintainability beautiful tough to mess with
  24. FUNCTIONS ARE COMMUTATIVE.val firstThing = doOneThing()val secondThing = doAnotherThing()val thirdThing = doTheLastThing(firstThing, secondThing) parallelization concurrency lazy evaluation powerful
  25. DATA IS IMMUTABLE.Once an object is created, it cannot be changed.If you need to change an object, make your own copy. a quick detour back to Java...String s1 = "san dimas high school football rules"String s2 = s1.toUpperCaseprintln("string 1: " + s1);println("string 2: " + s2); concurrency rollback of data simplicity powerful tough to mess with
  26. Functions are deterministicFunctions are encapsulatedFunctions are commutativeData is immutable Lets build.
  27. ...how?
  28. FUNCTIONS AS FIRST CLASS CITIZENS
  29. FIRST CLASS CITIZENSval longSkinnyThing: String = "this is a string"val listOfThem: List[String] = List("yarn","twine","thread")val freshNewLongSkinnyThing: String = spinFromFiber("wool")tieInAKnot(longSkinnyThing) class Rope(type:String) { override def toString(): String = "Youve put me on a diet!";}val longSkinnyThing: Rope = new Rope("nautical")val listOfThem: List[String] = List(longSkinnyThing, new Rope("climbing"), new Rope("clothesline"), new Rope("jump"))val freshNewLongSkinnyThing: Rope = spinFromFiber("hemp")tieInAKnot(longSkinnyThing)
  30. val addSpam: (String) => String = { (x:String) => x + " and Spam" }addSpam("Egg and Bacon") //result: "Egg and Bacon and Spam"val menuOptions = List(addSpam, withoutSpam)menuOptions(1)("Egg and Bacon and Spam") //result: "You cant have that" addSpams type is (String) => String(list of parameters types) => return type
  31. RETURNING FUNCTIONS FROM FUNCTIONSdef tagText(tag: String, text: String) = "<" + tag +">" + text +""val noReally = tagText("em", "pay attention!!!!") //result: <em>pay attention!!!!</em>def tagText2(tag: String) = { (text:String) =>"<" + tag +">" + text + "" }val tagWithAndSpam = tagText2("andSpam")val breakfast = tagWithAndSpam("Spam Bacon and Sausage") //result: <andSpam>Spam Bacon and Sausage</andSpam> beautiful powerful
  32. CURRYING YUM!
  33. HIGHER-ORDER FUNCTIONS
  34. FOR LOOP Javapublic void talkAboutFruit { Fruit[] fruits = { new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry") }; for (int i = 0; i < fruits.length; i++) { System.out.println("Hey the other day I ate a " + fruits[i]; }} Scala def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) for (i <- 0 until fruits.length) { System.out.println("Hey the other day I ate a " + fruits(i); }}
  35. LETS GET ABSTRACT a function that takes a list and a function (list of parameters types) => return type foreach(fruitList:List(fruits),theFunction: (Fruit) => Unit): Unit def foreach(fruitList:List(fruits), theFunction: (Fruit) => Unit) = { for (i <- 0 until fruitList.length) { theFunction(fruits(i)) }} def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val tellEm = { (f:Fruit) => System.out.println( "Hey the other day I ate a " + f) } foreach(fruits, tellEm) }}
  36. MORE ABSTRACTERER!foreach(theList:List(A), theFunction: (A) => Unit): Unitabstract class Collection[A] { ... def foreach(theFunction: (A) => Unit): Unit ...} def talkAboutFruit = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val tellEm = { (f:Fruit) => System.out.println( "Hey the other day I ate a " + f) } fruits.foreach(tellEm) }}
  37. THIS:abstract class Collection[A] { ... def foreach(theFunction: (A) => Unit): Unit = { for (i <- 0 until this.length) { theFunction(this(i)) } } ...} IS NOT HOW SCALA IMPLEMENTED FOREACH tough to mess with powerful
  38. SOMETHING A LITTLE JUICIERdef makePies: List[Pie] = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) var pies = List() for (i <- 0 until fruits.length) { new Pie(fruits(i)) :: pies } pies} on a collection of A, you can map(theFunction: (A) => B): Collection[B]def makePies: List[Pie] = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) val makePie = { (f: Fruit) => new Pie(f) } fruits.map(makePie)}
  39. ANONYMOUS FUNCTIONSval kindOfFruit: String = "blueberry"val blueberryFruit = new Fruit(kindOfFruit)val alsoBlueberry = new Fruit("blueberry")val makePie = { (f: Fruit) => new Pie(f) }fruits.map(makePie)//equivalent tofruits.map( { (f: Fruit) => new Pie(f) } )def makePies: List[Pie] = { val fruits = List(new Fruit("apple"), new Fruit("cherry"), new Fruit("strawberry")) fruits.map( { (f: Fruit) => new Pie(f) } )}def makePies(fruits: List[Fruit]) : List[Pie] = fruits.map( { (f: Fruit) => new Pie(f) } ) beautiful
  40. COLLECTION HANDLING FILTERval theList = List(new Fruit("apple"), new Fruit("pear"), new Fruit("cherry"), new Fruit("strawberry"), new Fruit("honeydew"))scala> theList.filter( { (f: Fruit) => f.isDelicious } )res0: List[Fruit] = List(apple, cherry, strawberry) FOLDscala> theList.fold("The fruits on this list are: ")( { (stringSoFar: String, f: Fruit) => stringSoFar + " " + f.name } )res1: String = "The fruits on this list are: apple pear cherry strawberry honeydew" REDUCEscala> theList.fold(0)( { (count: Int, f: Fruit) => count + " " + f.totalPieces } )res2: Int = 42300theList.reduce( { (f: Fruit) => f.totalPieces } )res3: Int = 42300
  41. NESTED FOR-LOOPS def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):List(Serving[Pie, IceCream]) { val servings = List[Serving[Pie,IceCream]]() for (p <- 0 until pies.length) { for (i <- 0 until iceCreams.length) { val serving = new Serving(p, i) serving :: servings } } servings} def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):List(Serving[Pie, IceCream]) { pies.map( { (p: Pie) => iceCreams.map( { (i: IceCream) => new Serving(p, i) } ) } )}
  42. IS THIS AN IMPROVEMENT?def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]): List(Serving[Pie, IceCream]) { val servingsLists = pies.map( { (p: Pie) => iceCreams.map( { (i: IceCream) => new Serving(p, i) } ) } ) servingsLists.flatten}
  43. FUNCTION COMPOSITION def bakeAPie(f: Fruit, c: Crust): Pie def eatAPie(p: Pie): HappyKelsey def bakeAndEatAPie(f: Fruit, c: Crust): HappyKelsey = eatAPie com pose bakeAPie //could also be written bakeAPie andThen eatAPieflatten compose map is flatMap, and its MAGIC
  44. FOR-YIELD def tryAllPairings(pies: List[Pie], iceCreams: List[IceCream]):List(Serving[Pie, IceCream]) { for { p <- pies i <- iceCreams } yield { new Serving(p,i) }} beautiful!
  45. FUN WITH FOR-YIELD def goodPairings(pies: List[Pie], iceCreams: List[IceCream]): List(Serving[Pie, IceCream]) { for { p <- pies i <- iceCreams val serving = new Serving(p,i) if (serving.isGood) } yield { serving }} def pleaseEverybody(audience: List[Person], pies: List[Pie], iceCreams: List[IceCream]): List(ThankYou) { for { person <- audience p <- pies i <- iceCreams val serving = new Serving(p,i) if (serving.isGood) } yield { person.feed(serving) }}
  46. partial applicationhigher order functionsfunction compositionfor-yield
  47. AND NOW FOR SOMETHING(NOT REALLY) COMPLETELY DIFFERENT
  48. NULL.
  49. YUCK public Serving<Pie, IceCream> serveBestALaMode(Pie key, Map<Pie, IceCream> pairings) { if(pairings != null) { IceCream iceCream = pairings.get(key); if(iceCream != null) { return new Serving(key, iceCream) } else { return null; } } }SCALA PROGRAMMING DOESNT USE NULL. YIPPEE!
  50. OPTIONOption[T] is either a Some with a value of type T inside, or None representing nothing. val someOption: Option[String] = Some("this is a value") val noneOption: Option[String] = None val theSomeValue = someOption.get //returns "this is a value" val someIsDefined = someOption.isDefined //returns true val theNoneValue = noneOption.get //throws NoSuchElementException val someIsDefined = someOption.isDefined //returns false
  51. def serveBestALaMode(key: Pie, pairings: Map[Pie, IceCream]): Option[Serving[Pie,IceCream]] = { iceCream: Option[IceCream] = pairings.get(key); if (iceCream.isDefined) { Some(new Serving(key, iceCream.get)) } else { None }}
  52. OPTION IS KIND OF LIKE A COLLECTION .MAPsomeOption.map( {(str:String) => str + " SAN DIMAS HIGH SCHOOL FOOTBALL RULES"} ) //returns Some("this is a value SAN DIMAS HIGH SCHOOL FOOTBALL RULES")noneOption.map( {(str:String) => str + " SAN DIMAS HIGH SCHOOL FOOTBALL RULES"} ) //returns None .FLATMAPval favoritePie: Option[Pie] = Some(rhubarb)favoritePie.map({ (pie: Pie) => pairings.get(pie) }) //returns Some(Some(butterPecan))--whoops!favoritePie.flatMap( { (pie: Pie) => pairings.get(pie) } ) //returns Some(butterPecan) .FILTERval todaysSpecial: Option[Pie]val myOrder = todaysSpecial.filter( { (pie: Pie) => (pie != butterPecan) }
  53. FOR-YIELD OVER OPTION for { pie <- todaysSpecial bestIceCream <- pairings.get(pie) iceCream <- availableFlavors.get(bestIceCream) } yield { myDessert} beautiful powerful tough to mess with
  54. OPTION IS A MONAD WHAT IS A MONAD?
  55. "Let’s look at what it is that makes Thing a monad.The first thing is that I can wrap up a value inside of anew Thing...We have a function of type A => Thing; a function which takes some value and wraps it up inside a new Thing. We also have this fancy bind function, which digs inside our Thing and allows a function which wesupply to use that value to create a new Thing. Scala calls this function “flatMap“.... What’s interesting here is the fact that bind is how you combine two things together in sequence. We start with one thing and use its value to compute a new thing." —Daniel Spiewak
  56. FLATMAP IS MAGIC flatMap hides our boilerplate. For Lists, it abstractsaway a for-loop, letting us create a new List from an existing list. For Options, it abstracts away a nullcheck, letting us create a new nullable value from an existing one. tough to mess with
  57. OTHER MONADSaccumulating errorsa cursor position in a database or filestates in a state machinean environment that changes powerful
  58. EXTRA CREDIT WHOAA SEMICOLON IS A MONAD
  59. partial applicationhigher order functionsfunction compositionfor-yieldmonads
  60. THE PSYCHOLOGY OFFUNCTIONAL PROGRAMMING
  61. READABILITY“Is Clojure code hard to understand? Imagine if every time you read Java source code and encountered syntax elements like if statements, for loops, and anonymous classes, you had to pause and puzzle over what they mean. There are certain things that must be obvious to a person who wants to be a productive Java developer. Likewise there are parts of Clojure syntax that must be obvious for one to efficiently read and understand code. Examples include being comfortable with the use of let, apply, map, filter, reduce and anonymous functions...”—R. Mark Volkmann
  62. DSLSclass HelloWorldSpec extends Specification { "The Hello world string" should { "contain 11 characters" in { "Hello world" must have size(11) } "start with Hello" in { "Hello world" must startWith("Hello") } "end with world" in { "Hello world" must endWith("world") } } } from specs2
  63. PURITY“The truth is that good programmers mix the styles quite a bit. We program imperatively when needed, and functionally when possible.” - Michael O. Church
  64. THANK YOU

×