Your SlideShare is downloading. ×
Practically Functional
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Practically Functional

2,844
views

Published on

Slides for my recent presentation at the CASE meetup, May 21st. Discusses functional programming features in Scala. Goes from basic FP features like higher-order functions all the way through to …

Slides for my recent presentation at the CASE meetup, May 21st. Discusses functional programming features in Scala. Goes from basic FP features like higher-order functions all the way through to monads.

Published in: Technology

2 Comments
3 Likes
Statistics
Notes
No Downloads
Views
Total Views
2,844
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
162
Comments
2
Likes
3
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Practically Functional Daniel Spiewak
  • 2. whoami  Author of Scala for Java Refugees and other articles on Scala and FP  Former editor Javalobby / EclipseZone  Engaged in academic research involving Scala DSLs and text parsing (ScalaBison, GLL Combinators, ScalaQL)
  • 3. Agenda  Define “functional programming” (sort of)  See some common elements of FP  Motivate why this stuff is useful in the real world (hopefully)  Show practical functional techniques and design patterns  Explain monads!  Hopefully pique your interest in learning and applying more of this
  • 4. Definitions  Q: What is “functional programming”?
  • 5. Definitions  Q: What is “functional programming”? ◦ A: Nobody knows!
  • 6. Definitions  Q: What is “purely-functional”?
  • 7. Definitions  Q: What is “purely-functional”? ◦ Everything is immutable (no variables)
  • 8. Definitions  Q: What is “purely-functional”? ◦ Everything is immutable (no variables) ◦ Absolutely no side-effects println(quot;Hello, World!quot;)
  • 9. Definitions  Q: What is “purely-functional”? ◦ Everything is immutable (no variables) ◦ Absolutely no side-effects ◦ Referential transparency
  • 10. Definitions  Q: What is “purely-functional”? ◦ Everything is immutable (no variables) ◦ Absolutely no side-effects ◦ Referential transparency ◦ Bondage discipline?
  • 11. Definitions  Scala is not purely-functional ◦ vars ◦ Mutable collections ◦ Uncontrolled side-effects (println)
  • 12. Definitions  Scala is not purely-functional ◦ vars ◦ Mutable collections ◦ Uncontrolled side-effects (println)  Is Scala a “functional language”?
  • 13. Functional Trademarks  Higher-order functions def foreach(f: String=>Unit) { f(quot;Whatquot;) f(quot;isquot;) f(quot;goingquot;) f(quot;on?quot;) }
  • 14. Functional Trademarks  Higher-order functions foreach { s => println(s) }
  • 15. Functional Trademarks  Higher-order functions  Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count! foreach(println)
  • 16. Functional Trademarks  Higher-order functions  Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count!  Singly-linked immutable lists (cons cells) val names = quot;Chrisquot; :: quot;Joequot; :: Nil val names2 = quot;Danielquot; :: names
  • 17. Functional Trademarks  Higher-order functions  Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count!  Singly-linked immutable lists (cons cells)  Usually some form of type-inference val me = quot;Danielquot; // equivalent to... val me: String = quot;Danielquot;
  • 18. Functional Trademarks  Higher-order functions  Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count!  Singly-linked immutable lists (cons cells)  Usually some form of type-inference foreach { s => println(s) }
  • 19. Functional Trademarks  Higher-order functions  Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count!  Singly-linked immutable lists (cons cells)  Usually some form of type-inference  Immutable by default (or encouraged) val me = quot;Danielquot; var me = quot;Danielquot;
  • 20. What does this buy you?  Modularity (separation of concerns)  Understandability  No more “spooky action at a distance” …
  • 21. What does this buy you? public class Company { private List<Person> employees; public List<Person> getEmployees() { return employees; } public void addEmployee(Person p) { if (p.isAlive()) { employees.add(p); } } }
  • 22. What does this buy you?  Modularity (separation of concerns)  Understandability  No more “spooky action at a distance”  Flexible libraries (more on this later)  Syntactic power (internal DSLs)
  • 23. What does this buy you? quot;vectorquot; should { quot;store a single elementquot; in { val prop = forAll { (i: Int, e: Int) => i >= 0 ==> { (vector(0) = e)(0) mustEqual e } } prop must pass } quot;implement lengthquot; in { val prop = forAll { list: List[Int] => val vec = Vector(list:_*) vec.length mustEqual list.length } prop must pass } }
  • 24. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods
  • 25. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods def factorial(n: Int) = { var back = 1 for (i <- 1 to n) { back *= i } back }
  • 26. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods def factorial(n: Int): Int = { if (n == 1) 1 else n * factorial(n - 1) }
  • 27. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods def factorial(n: Int) = { def loop(n: Int, acc: Int): Int = { if (n == 1) acc else loop(n - 1, acc * n) } loop(n, 1) }
  • 28. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods  Higher-order functions instead of recursion
  • 29. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods  Higher-order functions instead of recursion  Combinators instead of higher-order functions
  • 30. Functional Idioms  Recursion instead of loops ◦ Scala helps with this by allowing methods within methods  Higher-order functions instead of recursion  Combinators instead of higher-order functions  Monads!
  • 31. Example #1 Retrieve structured, formatted data from across multiple .properties files and multiple keys within those files. # daniel.properties # tim.properties name.first = Daniel name.first = Timothy name.last = Spiewak name.last = Olmsted age = 21 age = 22
  • 32. Example #1  Using loops
  • 33. def toInt(s: String) = try { s.toInt } catch { case _ => null } // uninteresting and ugly def readFile(file: String): Map[String, String] = { import collection.jcl.Hashtable try { val is = new BufferedInputStream(new FileInputStream(file)) val p = new Properties p.load(is) is.close() new Hashtable(p).asInstanceOf[Hashtable[String, String]] } catch { case _ => null } }
  • 34. import collection.mutable.ListBuffer def readPeople(files: List[String]): List[Person] = { val back = new ListBuffer[Person] for (file <- files) { val props = readFile(file) if (props != null) { if (props.contains(quot;name.firstquot;) && props.contains(quot;name.lastquot;) && props.contains(quot;agequot;)) { val age = toInt(props(quot;agequot;)) if (age != null) back += new Person(props(quot;name.firstquot;), props(quot;name.lastquot;), age) } } } back.toList }
  • 35. Example #1  Using loops  Recursive
  • 36. def readPeople(files: List[String]): List[Person] = files match { case file :: tail => { val props = readFile(file) val back = if (props != null) { if (props.contains(quot;name.firstquot;) && props.contains(quot;name.lastquot;) && props.contains(quot;agequot;)) { val age = toInt(props(quot;agequot;)) if (age != null) new Person(props(quot;name.firstquot;), props(quot;name.lastquot;), age) else null } else null } else null if (back != null) back :: readPeople(tail) else readPeople(tail) } case Nil => Nil }
  • 37. Example #1  Loops  Recursion  Higher-order functions
  • 38. def readPeople(files: List[String]): List[Person] = { files.foldRight(List[String]()) { (file, people) => val props = readFile(file) val back = if (props != null) { if (props.contains(quot;name.firstquot;) && props.contains(quot;name.lastquot;) && props.contains(quot;agequot;)) { val age = toInt(props(quot;agequot;)) if (age != null) new Person(props(quot;name.firstquot;), props(quot;name.lastquot;), age) else null } else null } else null if (back != null) back :: people else people } }
  • 39. Example #1  Loops  Recursion  Higher-order functions …  Monads!
  • 40. def toInt(s: String) = try { Some(s.toInt) } catch { case _ => None } // uninteresting and ugly def readFile(file: String): Option[Map[String, String]] = { import collection.jcl.Hashtable try { val is = new BufferedInputStream(new FileInputStream(file)) val p = new Properties p.load(is) is.close() Some(new Hashtable(p).asInstanceOf[Hashtable[String, String]]) } catch { case _ => None } }
  • 41. def readPeople(files: List[String]): List[Person] = { for { file <- files props <- readFile(file) firstName <- props get quot;name.firstquot; lastName <- props get quot;name.lastquot; ageString <- props get quot;agequot; age <- toInt(ageString) } yield new Person(firstName, lastName, age) }
  • 42. Example #1  Loops  Recursion  Higher-order functions  Combinators  Monads!
  • 43. def readPeople(files: List[String]) = { import Function._ files flatMap readFile flatMap { props => val fNames = props get quot;name.firstquot; val names = fNames flatMap { (_, props get quot;name.lastquot;) } val data = names flatMap { case (fn, ln) => (fn, ln, props get quot;agequot; map toInt) } data map tupled(new Person _) } }
  • 44. What did we just see?  foldLeft / foldRight ◦ Catamorphisms ◦ Use when you want to reduce all of the elements of a collection into a single result ◦ Capable of almost anything!
  • 45. What did we just see?  foldLeft / foldRight def sum(nums: List[Int]) = { nums.foldLeft(0) { (x, y) => x + y } }
  • 46. What did we just see?  foldLeft / foldRight def sum(nums: List[Int]) = { nums.foldLeft(0) { _ + _ } }
  • 47. What did we just see?  foldLeft / foldRight def sum(nums: List[Int]) = { (0 /: nums) { _ + _ } }
  • 48. What did we just see?  foldLeft / foldRight  map ◦ Use when you want to transform every element of a collection, leaving the results in the corresponding location within a new collection
  • 49. What did we just see?  foldLeft / foldRight  map val nums = List(quot;1quot;, quot;2quot;, quot;3quot;, quot;4quot;, quot;5quot;) nums map { str => str.toInt }
  • 50. What did we just see?  foldLeft / foldRight  map val nums = List(quot;1quot;, quot;2quot;, quot;3quot;, quot;4quot;, quot;5quot;) nums map { _.toInt }
  • 51. What did we just see?  foldLeft / foldRight  map  flatMap (has two meanings) ◦ Collections: Use when you want to transform every element optionally ◦ Monads: Should have really been called “bind” (or >>=). More later…
  • 52. What did we just see?  foldLeft / foldRight  map  flatMap (has two meanings) def toCharArray(arr: Array[String]) = { arr flatMap { _.toCharArray } } toCharArray(Array(quot;Danielquot;, quot;Spiewakquot;)) // => Array('D', 'a', 'n', 'i', 'e', 'l', 'S', 'p', 'i', 'e', 'w', 'a', 'k')
  • 53. Other Common Util Methods  filter (used in for-comprehensions) val nums = List(1, 2, 3, 4, 5) nums filter { _ % 2 == 0 }
  • 54. Other Common Util Methods  filter (used in for-comprehensions) val nums = List(1, 2, 3, 4, 5) nums filter (0 == 2 %)
  • 55. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0) val evens = List(2, 4, 6) val odds = List(1, 3, 5) evens zip odds // => List((1, 2), (3, 4), (5, 6))
  • 56. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0)  forall and exists val nums = List(1, 2, 3, 4, 5) nums forall { _ % 2 == 0 } // => false
  • 57. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0)  forall and exists val nums = List(1, 2, 3, 4, 5) nums exists { _ % 2 == 0 } // => true
  • 58. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0)  forall and exists  take and drop val nums = List(5, 4, 3, 2, 1) nums take 2 // => List(5, 4)
  • 59. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0)  forall and exists  take and drop val nums = List(5, 4, 3, 2, 1) nums drop 2 // => List(3, 2, 1)
  • 60. Other Common Util Methods  filter (used in for-comprehensions)  zip / zipWithIndex ◦ zipWith (not available pre-2.8.0)  forall and exists  take and drop  foreach val names = List(quot;Danielquot;, quot;Chrisquot;) names foreach println
  • 61. Example #2 Comparing the prefix of a List[Char] to a given string. List[Char] String Result List('d', 'a', 'n', 'i', 'e', 'l') quot;danquot; true List('d', 'a', 'n', 'i', 'e', 'l') quot;ielquot; false List('t', 'e', 's', 't') quot;testingquot; false List('t', 'e', 's', 't') quot;testquot; true
  • 62. def isPrefix(chars: List[Char], str: String) = { if (chars.lengthCompare(str.length) < 0) { false } else { val trunc = chars take str.length trunc.zipWithIndex forall { case (c, i) => c == str(i) } } }
  • 63. More About Combinators  The “Essence of Functional Programming”  Combine simple things to solve complex problems  Very high level  Think about Lego™ bricks
  • 64. More About Combinators  The best example: Parser Combinators def expr: Parser[Int] = ( num ~ quot;+quot; ~ expr ^^ { case (x, _, y) => x + y } | num ~ quot;-quot; ~ expr ^^ { case (x, _, y) => x - y } | num ) def num = quot;quot;quot;d+quot;quot;quot;.r ^^ { _.toInt }
  • 65. More About Combinators  The best example: Parser Combinators def expr: Parser[Int] = ( num ~ quot;+quot; ~ expr ^^ { case (x, _, y) => x + y } | num ~ quot;-quot; ~ expr ^^ { case (x, _, y) => x - y } | num ) def num = quot;quot;quot;d+quot;quot;quot;.r ^^ { _.toInt } expr(quot;12 + 7 - 4quot;) // => Success(15) expr(quot;42quot;) // => Success(42)
  • 66. More About Combinators  Three Types of Combinators ◦ Sequential (first a, then b) a ~ b
  • 67. More About Combinators  Three Types of Combinators ◦ Sequential (first a, then b) ◦ Disjunctive (either a, or b) a | b
  • 68. More About Combinators  Three Types of Combinators ◦ Sequential (first a, then b) ◦ Disjunctive (either a, or b) ◦ Literal (exactly foo) quot;fooquot;
  • 69. More About Combinators  Three Types of Combinators ◦ Sequential (first a, then b) ◦ Disjunctive (either a, or b) ◦ Literal (exactly foo)  Note: Our example uses a regular expression parser, but that is only a generalization of the literal parser
  • 70. More About Combinators  Seldom created, often used  Good for problems which split into smaller sub-problems
  • 71. March of the Monads  Monads are not scary
  • 72. March of the Monads  Monads are not scary  Monad explanations are scary
  • 73. March of the Monads  Monads are little containers for encapsulating something ◦ What the “something” is depends on the monad  An instance of a monad can be “bound” together with another instance of that monad  Most combinators are monads
  • 74. March of the Monads  All monads have ◦ A type constructor class Option[A] { … } ◦ A single-argument constructor new Some(quot;one to watch over mequot;) ◦ A flatMap method which behaves properly a flatMap { v => v.next }
  • 75. March of the Monads
  • 76. March of the Monads  Option ◦ This is what the Groovy folks really wanted when they designed the “Elvis Operator”  Parser ◦ Sequential parser is really two bound parsers ◦ Disjunctive parser uses an optional monadic function: orElse ◦ Literal parser is the one-argument constructor  Function1 (sort of) ◦ We could say that function composition is
  • 77. Learn More  Read my blog! :-) ◦ http://www.codecommit.com/blog  Some better sources… ◦ http://apocalisp.wordpress.com/ ◦ http://michid.wordpress.com/ ◦ http://joelneely.wordpress.com/ ◦ http://scala-blogs.org  A really good paper… ◦ Monadic Parser Combinators (1996; Hutton, Meijer)