1 / 77

Practically Functional

Practically Functional. Daniel Spiewak. 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 ). Agenda.

lynton
Download Presentation

Practically Functional

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation 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 stuff

  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("Hello, World!")

  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 defforeach(f: String=>Unit) { f("What") f("is") f("going") f("on?") }

  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 = "Chris"::"Joe"::Nil val names2 = "Daniel":: 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 = "Daniel" // equivalent to... val me: String = "Daniel"

  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 = "Daniel" var me = "Daniel"

  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? "vector" should { "store a single element" in { val prop = forAll { (i: Int, e: Int) => i>=0==> { (vector(0) = e)(0) mustEqual e } } prop must pass } "implement length"in { val prop = forAll { list: List[Int] => valvec = Vector(list:_*) vec.lengthmustEquallist.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 deffactorial(n: Int) = { var back = 1 for (i <- 1to n) { back *=i } back }

  26. Functional Idioms • Recursion instead of loops • Scala helps with this by allowing methods within methods deffactorial(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 deffactorial(n: Int) = { defloop(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 name.first = Daniel name.last = Spiewak age = 21 # tim.properties name.first = Timothy name.last = Olmsted age = 22

  32. Example #1 • Using loops

  33. deftoInt(s: String) = try { s.toInt } catch { case _ => null } // uninteresting and ugly defreadFile(file: String): Map[String, String] = { importcollection.jcl.Hashtable try { val is = newBufferedInputStream(new FileInputStream(file)) val p = new Properties p.load(is) is.close() newHashtable(p).asInstanceOf[Hashtable[String, String]] } catch { case _ => null } }

  34. importcollection.mutable.ListBuffer defreadPeople(files: List[String]): List[Person] = { val back = newListBuffer[Person] for (file <- files) { val props = readFile(file) if (props !=null) { if (props.contains("name.first") && props.contains("name.last") && props.contains("age")) { val age = toInt(props("age")) if (age !=null) back +=new Person(props("name.first"), props("name.last"), age) } } } back.toList }

  35. Example #1 • Using loops • Recursive

  36. defreadPeople(files: List[String]): List[Person] = files match { case file :: tail => { val props = readFile(file) val back = if (props !=null) { if (props.contains("name.first") && props.contains("name.last") && props.contains("age")) { val age = toInt(props("age")) if (age !=null) new Person(props("name.first"), props("name.last"), age) else null } else null } else null if (back !=null) back :: readPeople(tail) else readPeople(tail) } caseNil => Nil }

  37. Example #1 • Loops • Recursion • Higher-order functions

  38. defreadPeople(files: List[String]): List[Person] = { files.foldRight(List[String]()) { (file, people) => val props = readFile(file) val back = if (props !=null) { if (props.contains("name.first") && props.contains("name.last") && props.contains("age")) { val age = toInt(props("age")) if (age !=null) new Person(props("name.first"), props("name.last"), age) else null } else null } else null if (back !=null) back :: people else people } }

  39. Example #1 • Loops • Recursion • Higher-order functions • … • Monads!

  40. deftoInt(s: String) = try { Some(s.toInt) } catch { case _ => None } // uninteresting and ugly defreadFile(file: String): Option[Map[String, String]] = { importcollection.jcl.Hashtable try { val is = newBufferedInputStream(newFileInputStream(file)) val p = new Properties p.load(is) is.close() Some(newHashtable(p).asInstanceOf[Hashtable[String, String]]) } catch { case _ => None } }

  41. defreadPeople(files: List[String]): List[Person] = { for { file <- files props <- readFile(file) firstName <- props get"name.first" lastName <- props get"name.last" ageString <- props get"age" age <- toInt(ageString) } yield new Person(firstName, lastName, age) }

  42. Example #1 • Loops • Recursion • Higher-order functions • Combinators • Monads!

  43. defreadPeople(files: List[String]) = { importFunction._ files flatMapreadFileflatMap { props => valfNames = props get"name.first" val names = fNamesflatMap { (_, props get"name.last") } val data = names flatMap { case (fn, ln) => (fn, ln, props get"age"maptoInt) } data maptupled(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 defsum(nums: List[Int]) = { nums.foldLeft(0) { (x, y) => x + y } }

  46. What did we just see? • foldLeft / foldRight defsum(nums: List[Int]) = { nums.foldLeft(0) { _ + _ } }

  47. What did we just see? • foldLeft / foldRight defsum(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 valnums = List("1", "2", "3", "4", "5") numsmap { str => str.toInt }

  50. What did we just see? • foldLeft / foldRight • map valnums = List("1", "2", "3", "4", "5") numsmap { _.toInt }

More Related