Practically Functional Daniel Spiewak whoami Author of Scala

































![import collection. mutable. List. Buffer def read. People(files: List[String]): List[Person] = { val back import collection. mutable. List. Buffer def read. People(files: List[String]): List[Person] = { val back](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-34.jpg)

![def read. People(files: List[String]): List[Person] = files match { case file : : tail def read. People(files: List[String]): List[Person] = files match { case file : : tail](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-36.jpg)

![def read. People(files: List[String]): List[Person] = { files. fold. Right(List[String]()) { (file, people) => def read. People(files: List[String]): List[Person] = { files. fold. Right(List[String]()) { (file, people) =>](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-38.jpg)


![def read. People(files: List[String]): List[Person] = { for { file <- files props <- def read. People(files: List[String]): List[Person] = { for { file <- files props <-](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-41.jpg)

![def read. People(files: List[String]) = { import Function. _ files flat. Map read. File def read. People(files: List[String]) = { import Function. _ files flat. Map read. File](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-43.jpg)

![What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) =](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-45.jpg)
![What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) =](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-46.jpg)
![What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) =](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-47.jpg)













![Example #2 Comparing the prefix of a List[Char] to a given string. List[Char] String Example #2 Comparing the prefix of a List[Char] to a given string. List[Char] String](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-61.jpg)
![def is. Prefix(chars: List[Char], str: String) = { if (chars. length. Compare(str. length) < def is. Prefix(chars: List[Char], str: String) = { if (chars. length. Compare(str. length) <](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-62.jpg)

![More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-64.jpg)
![More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-65.jpg)








![March of the Monads �All monads have ◦ A type constructor class Option[A] { March of the Monads �All monads have ◦ A type constructor class Option[A] {](https://slidetodoc.com/presentation_image/d278e554105527808dcc612537868a69/image-74.jpg)



- Slides: 77
Practically Functional Daniel Spiewak
whoami �Author of Scala for Java Refugees and other articles on Scala and FP �Former editor Javalobby / Eclipse. Zone �Engaged in academic research involving Scala DSLs and text parsing (Scala. Bison, GLL Combinators, Scala. QL)
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
Definitions �Q: What is “functional programming”?
Definitions �Q: What is “functional programming”? ◦ A: Nobody knows!
Definitions �Q: What is “purely-functional”?
Definitions �Q: What is “purely-functional”? ◦ Everything is immutable (no variables)
Definitions �Q: What is “purely-functional”? ◦ Everything is immutable (no variables) ◦ Absolutely no side-effects println("Hello, World!")
Definitions �Q: What is “purely-functional”? ◦ Everything is immutable (no variables) ◦ Absolutely no side-effects ◦ Referential transparency
Definitions �Q: ◦ ◦ What is “purely-functional”? Everything is immutable (no variables) Absolutely no side-effects Referential transparency Bondage discipline?
Definitions �Scala is not purely-functional ◦ vars ◦ Mutable collections ◦ Uncontrolled side-effects (println)
Definitions �Scala is not purely-functional ◦ vars ◦ Mutable collections ◦ Uncontrolled side-effects (println) �Is Scala a “functional language”?
Functional Trademarks �Higher-order functions def foreach(f: String=>Unit) { f("What") f("is") f("going") f("on? ") }
Functional Trademarks �Higher-order functions foreach { s => println(s) }
Functional Trademarks �Higher-order functions �Closures are anonymous functions ◦ Ruby, Groovy, Python; none of these count! foreach(println)
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 names 2 = "Daniel" : : names
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"
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) }
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"
What does this buy you? �Modularity (separation of concerns) �Understandability �No more “spooky action at a distance” �…
What does this buy you? public class Company { private List<Person> employees; public List<Person> get. Employees() { return employees; } public void add. Employee(Person p) { if (p. is. Alive()) { employees. add(p); } } }
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)
What does this buy you? "vector" should { "store a single element" in { val prop = for. All { (i: Int, e: Int) => i >= 0 ==> { (vector(0) = e)(0) must. Equal e } } prop must pass } "implement length" in { val prop = for. All { list: List[Int] => val vec = Vector(list: _*) vec. length must. Equal list. length } prop must pass } }
Functional Idioms �Recursion instead of loops ◦ Scala helps with this by allowing methods within methods
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 }
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) }
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) }
Functional Idioms �Recursion instead of loops ◦ Scala helps with this by allowing methods within methods �Higher-order recursion functions instead of
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
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!
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. last = Spiewak age = 21 name. first = Timothy name. last = Olmsted age = 22
Example #1 �Using loops
def to. Int(s: String) = try { s. to. Int } catch { case _ => null } // uninteresting and ugly def read. File(file: String): Map[String, String] = { import collection. jcl. Hashtable try { val is = new Buffered. Input. Stream(new File. Input. Stream(file)) val p = new Properties p. load(is) is. close() new Hashtable(p). as. Instance. Of[Hashtable[String, String]] } catch { case _ => null } }
import collection. mutable. List. Buffer def read. People(files: List[String]): List[Person] = { val back = new List. Buffer[Person] for (file <- files) { val props = read. File(file) if (props != null) { if (props. contains("name. first") && props. contains("name. last") && props. contains("age")) { val age = to. Int(props("age")) if (age != null) back += new Person(props("name. first"), props("name. last"), age) } } } back. to. List }
Example #1 �Using loops �Recursive
def read. People(files: List[String]): List[Person] = files match { case file : : tail => { val props = read. File(file) val back = if (props != null) { if (props. contains("name. first") && props. contains("name. last") && props. contains("age")) { val age = to. Int(props("age")) if (age != null) new Person(props("name. first"), props("name. last"), age) else null } else null if (back != null) back : : read. People(tail) else read. People(tail) } case Nil => Nil }
Example #1 �Loops �Recursion �Higher-order functions
def read. People(files: List[String]): List[Person] = { files. fold. Right(List[String]()) { (file, people) => val props = read. File(file) val back = if (props != null) { if (props. contains("name. first") && props. contains("name. last") && props. contains("age")) { val age = to. Int(props("age")) if (age != null) new Person(props("name. first"), props("name. last"), age) else null } else null if (back != null) back : : people else people } }
Example #1 �Loops �Recursion �Higher-order �… �Monads! functions
def to. Int(s: String) = try { Some(s. to. Int) } catch { case _ => None } // uninteresting and ugly def read. File(file: String): Option[Map[String, String]] = { import collection. jcl. Hashtable try { val is = new Buffered. Input. Stream(new File. Input. Stream(file)) val p = new Properties p. load(is) is. close() Some(new Hashtable(p). as. Instance. Of[Hashtable[String, String]]) } catch { case _ => None } }
def read. People(files: List[String]): List[Person] = { for { file <- files props <- read. File(file) first. Name <- props get "name. first" last. Name <- props get "name. last" age. String <- props get "age" age <- to. Int(age. String) } yield new Person(first. Name, last. Name, age) }
Example #1 �Loops �Recursion �Higher-order �Combinators �Monads! functions
def read. People(files: List[String]) = { import Function. _ files flat. Map read. File flat. Map { props => val f. Names = props get "name. first" val names = f. Names flat. Map { (_, props get "name. last") } val data = names flat. Map { case (fn, ln) => (fn, ln, props get "age" map to. Int) } data map tupled(new Person _) } }
What did we just see? �fold. Left / fold. Right ◦ Catamorphisms ◦ Use when you want to reduce all of the elements of a collection into a single result ◦ Capable of almost anything!
What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = { nums. fold. Left(0) { (x, y) => x + y } }
What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = { nums. fold. Left(0) { _ + _ } }
What did we just see? �fold. Left / fold. Right def sum(nums: List[Int]) = { (0 /: nums) { _ + _ } }
What did we just see? �fold. Left / fold. Right �map ◦ Use when you want to transform every element of a collection, leaving the results in the corresponding location within a new collection
What did we just see? �fold. Left / fold. Right �map val nums = List("1", "2", "3", "4", "5") nums map { str => str. to. Int }
What did we just see? �fold. Left / fold. Right �map val nums = List("1", "2", "3", "4", "5") nums map { _. to. Int }
What did we just see? �fold. Left / fold. Right �map �flat. Map (has two meanings) ◦ Collections: Use when you want to transform every element optionally ◦ Monads: Should have really been called “bind” (or >>=). More later…
What did we just see? �fold. Left / fold. Right �map �flat. Map (has two meanings) def to. Char. Array(arr: Array[String]) = { arr flat. Map { _. to. Char. Array } } to. Char. Array("Daniel", "Spiewak")) // => Array('D', 'a', 'n', 'i', 'e', 'l', 'S', 'p', 'i', 'e', 'w', 'a', 'k')
Other Common Util Methods �filter (used in for-comprehensions) val nums = List(1, 2, 3, 4, 5) nums filter { _ % 2 == 0 }
Other Common Util Methods �filter (used in for-comprehensions) val nums = List(1, 2, 3, 4, 5) nums filter (0 == 2 %)
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (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))
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (not available pre-2. 8. 0) �forall and exists val nums = List(1, 2, 3, 4, 5) nums forall { _ % 2 == 0 } // => false
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (not available pre-2. 8. 0) �forall and exists val nums = List(1, 2, 3, 4, 5) nums exists { _ % 2 == 0 } // => true
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (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)
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (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)
Other Common Util Methods �filter (used in for-comprehensions) �zip / zip. With. Index ◦ zip. With (not available pre-2. 8. 0) �forall and exists �take and drop �foreach val names = List("Daniel", "Chris") names foreach println
Example #2 Comparing the prefix of a List[Char] to a given string. List[Char] String Result List('d', 'a', 'n', 'i', 'e', 'l') "dan" true List('d', 'a', 'n', 'i', 'e', 'l') "iel" false List('t', 'e', 's', 't') "testing" false List('t', 'e', 's', 't') "test" true
def is. Prefix(chars: List[Char], str: String) = { if (chars. length. Compare(str. length) < 0) { false } else { val trunc = chars take str. length trunc. zip. With. Index forall { case (c, i) => c == str(i) } } }
More About Combinators �The “Essence of Functional Programming” �Combine simple things to solve complex problems �Very high level �Think about Lego™ bricks
More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num ~ "+" ~ expr ^^ { case (x, _, y) => x + y } | num ~ "-" ~ expr ^^ { case (x, _, y) => x - y } | num ) def num = """d+""". r ^^ { _. to. Int }
More About Combinators �The best example: Parser Combinators def expr: Parser[Int] = ( num ~ "+" ~ expr ^^ { case (x, _, y) => x + y } | num ~ "-" ~ expr ^^ { case (x, _, y) => x - y } | num ) def num = """d+""". r ^^ { _. to. Int } expr("12 + 7 - 4") // => Success(15) expr("42") // => Success(42)
More About Combinators �Three Types of Combinators ◦ Sequential (first a, then b) a ~ b
More About Combinators �Three Types of Combinators ◦ Sequential (first a, then b) ◦ Disjunctive (either a, or b) a | b
More About Combinators �Three Types of Combinators ◦ Sequential (first a, then b) ◦ Disjunctive (either a, or b) ◦ Literal (exactly foo) "foo"
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
More About Combinators �Seldom created, often used �Good for problems which split into smaller sub-problems
March of the Monads �Monads are not scary
March of the Monads �Monads are not scary �Monad explanations are scary
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
March of the Monads �All monads have ◦ A type constructor class Option[A] { … } ◦ A single-argument constructor new Some("one to watch over me") ◦ A flat. Map method which behaves properly a flat. Map { v => v. next }
March of the Monads
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: or. Else ◦ Literal parser is the one-argument constructor �Function 1 (sort of) ◦ We could say that function composition is
Learn More �Read my blog! : -) ◦ http: //www. codecommit. com/blog �Some ◦ ◦ �A better sources… http: //apocalisp. wordpress. com/ http: //michid. wordpress. com/ http: //joelneely. wordpress. com/ http: //scala-blogs. org really good paper… ◦ Monadic Parser Combinators (1996; Hutton, Meijer)