PATTERN MATCHING

Scala has a built-in general pattern matching mechanism. It allows to match on any sort of data with a first-match policy. Here is a small example which shows how to match against an integer value:

object MatchTest1 extends App {

def matchTest(x: Int): String = x match {

case 1 => “one”

case 2 => “two”

case _ => “many”

}

println(matchTest(3))

}

 

The block with the case statements defines a function which maps integers to strings. The match keyword provides a convenient way of applying a function (like the pattern matching function above) to an object.

 

Scala’s pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.

 

Pattern matching returns something:

 

val stuff = “blue”

 

val myStuff = stuff match {

case “red” ⇒

println(“RED”); 1

case “blue” ⇒

println(“BLUE”); 2

case “green” ⇒

println(“GREEN”); 3

case _ ⇒ println(stuff); 0 //case _ will trigger if all other cases fail.

}

 

myStuff should be(2)

 

Pattern matching can return complex somethings:

 

val stuff = “blue”

 

val myStuff = stuff match {

case “red” ⇒ (255, 0, 0)

case “green” ⇒ (0, 255, 0)

case “blue” ⇒ (0, 0, 255)

case _ ⇒ println(stuff); 0

}

 

myStuff should be(0, 0, 255)

 

Pattern matching can match complex expressions:

 

def goldilocks(expr: Any) = expr match {

case (“porridge”, “Papa”) ⇒ “Papa eating porridge”

case (“porridge”, “Mama”) ⇒ “Mama eating porridge”

case (“porridge”, “Baby”) ⇒ “Baby eating porridge”

case _ ⇒ “what?”

}

 

goldilocks((“porridge”, “Mama”)) should be(“Mama eating porridge”)

 

Pattern matching can wildcard parts of expressions:

 

def goldilocks(expr: Any) = expr match {

case (“porridge”, _) ⇒ “eating”

case (“chair”, “Mama”) ⇒ “sitting”

case (“bed”, “Baby”) ⇒ “sleeping”

case _ ⇒ “what?”

}

 

goldilocks((“porridge”, “Papa”)) should be(“eating”)

goldilocks((“chair”, “Mama”)) should be(“sitting”)

 

Pattern matching can substitute parts of expressions:

 

def goldilocks(expr: Any) = expr match {

case (“porridge”, bear) ⇒ bear + ” said someone’s been eating my porridge”

case (“chair”, bear) ⇒ bear + ” said someone’s been sitting in my chair”

case (“bed”, bear) ⇒ bear + ” said someone’s been sleeping in my bed”

case _ ⇒ “what?”

}

 

goldilocks((“porridge”, “Papa”)) should be(“Papa said someone’s been eating my porridge”)

 

goldilocks((“chair”, “Mama”)) should be(“Mama said someone’s been sitting in my chair”)

 

A backquote can be used to refer to a stable variable in scope to create a case statement. This prevents what is called “Variable Shadowing”

 

val foodItem = “porridge”

 

def goldilocks(expr: Any) = expr match {

case (foodItem, _) ⇒ “eating”

case (“chair”, “Mama”) ⇒ “sitting”

case (“bed”, “Baby”) ⇒ “sleeping”

case _ ⇒ “what?”

}

 

goldilocks((“porridge”, “Papa”)) should be(“eating”)

goldilocks((“chair”, “Mama”)) should be(“sitting”)

goldilocks((“porridge”, “Cousin”)) should be(“eating”)

goldilocks((“beer”, “Cousin”)) should be(“what?”)

 

A backquote can be used to refer to a method parameter as a stable variable to create a case statement:

 

def patternEquals(i: Int, j: Int) = j match {

case i ⇒ true

case _ ⇒ false

}

patternEquals(3, 3) should be(true)

patternEquals(7, 9) should be(false)

patternEquals(9, 9) should be(true)

 

To pattern match against a List, the list can be broken out into parts, in this case the head x and the tail xs. Since the case doesn’t terminate in Nil, xs is interpreted as the rest of the list:

 

val secondElement = List(1, 2, 3) match {

case x :: xs ⇒ xs.head

case _ ⇒ 0

}

 

secondElement should be(2)

To obtain the second element you can expand on the pattern. Where x is the first element, y is the second element, and xs is the rest:

 

val secondElement = List(1, 2, 3) match {

case x :: y :: xs ⇒ y

case _ ⇒ 0

}

 

secondElement should be(2)

 

Same koan as above, but we are pattern matching a list with only one item!

 

val secondElement = List(1) match {

case x :: y :: xs ⇒ y

case _ ⇒ 0

}

 

secondElement should be(0)

 

To pattern match against List, you can also establish a pattern match if you know the exact number of elements in a List:

 

val r = List(1, 2, 3) match {

case x :: y :: Nil ⇒ y

case _ ⇒ 0

}

 

r should be(0)

Advertisements

[Scala]CASE CLASSES

Scala supports the notion of case classes. Case classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching.

Here is an example for a class hierarchy which consists of an abstract super class Term and three concrete case classes Var, Fun, and App.

abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term
This class hierarchy can be used to represent terms of the untyped lambda calculus. To facilitate the construction of case class instances, Scala does not require that the new primitive is used. One can simply use the class name as a function.

Here is an example:

Fun(“x”, Fun(“y”, App(Var(“x”), Var(“y”))))
The constructor parameters of case classes are treated as public values and can be accessed directly.

val x = Var(“x”)
Console.println(x.name)
For every case class the Scala compiler generates equals method which implements structural equality and atoString method. For instance:

val x1 = Var(“x”)
val x2 = Var(“x”)
val y1 = Var(“y”)
println(“” + x1 + ” == ” + x2 + ” => ” + (x1 == x2))
println(“” + x1 + ” == ” + y1 + ” => ” + (x1 == y1))
will print

Var(x) == Var(x) => true
Var(x) == Var(y) => false
It only makes sense to define case classes if pattern matching is used to decompose data structures. The following object defines a pretty printer function for our lambda calculus representation:

object TermTest extends Application {
def printTerm(term: Term) {
term match {
case Var(n) =>
print(n)
case Fun(x, b) =>
print(“^” + x + “.”)
printTerm(b)
case App(f, v) =>
Console.print(“(“)
printTerm(f)
print(” “)
printTerm(v)
print(“)”)
}
}
def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false
}
val id = Fun(“x”, Var(“x”))
val t = Fun(“x”, Fun(“y”, App(Var(“x”), Var(“y”))))
printTerm(t)
println
println(isIdentityFun(id))
println(isIdentityFun(t))
}
In our example, the function print is expressed as a pattern matching statement starting with the match keyword and consisting of sequences of case Pattern => Body clauses.

The program above also defines a function isIdentityFun which checks if a given term corresponds to a simple identity function. This example uses deep patterns and guards. After matching a pattern with a given value, the guard (defined after the keyword if) is evaluated. If it returns true, the match succeeds; otherwise, it fails and the next pattern will be tried.

Case classes have an automatic equals method that works:

case class Person(first: String, last: String)

val p1 = new Person(“Fred”, “Jones”)
val p2 = new Person(“Shaggy”, “Rogers”)
val p3 = new Person(“Fred”, “Jones”)

(p1 == p2) should be(false)
(p1 == p3) should be(true)
(p1 eq p2) should be(false)
(p1 eq p3) should be(false)
Case classes have an automatic hashcode method that works:

case class Person(first: String, last: String)

val p1 = new Person(“Fred”, “Jones”)
val p2 = new Person(“Shaggy”, “Rogers”)
val p3 = new Person(“Fred”, “Jones”)

(p1.hashCode == p2.hashCode) should be(false)
(p1.hashCode == p3.hashCode) should be(true)
Case classes can be created in a convenient way:

case class Dog(name: String, breed: String)

val d1 = Dog(“Scooby”, “Doberman”)
val d2 = Dog(“Rex”, “Custom”)
val d3 = new Dog(“Scooby”, “Doberman”) // the old way of creating using new

(d1 == d3) should be(true)
(d1 == d2) should be(false)
(d2 == d3) should be(false)

toStringMethodCaseClasses

Case classes have a convenient toString method defined:

Run
case class Dog(name: String, breed: String)
val d1 = Dog(“Scooby”, “Doberman”)
d1.toString should be()
Case classes have automatic properties:

case class Dog(name: String, breed: String)

val d1 = Dog(“Scooby”, “Doberman”)
d1.name should be(“Scooby”)
d1.breed should be(“Doberman”)
Case classes can have mutable properties:

case class Dog(var name: String, breed: String) // you can rename a dog, but change its breed? nah!
val d1 = Dog(“Scooby”, “Doberman”)

d1.name should be(“Scooby”)
d1.breed should be(“Doberman”)

d1.name = “Scooby Doo” // but is it a good idea?

d1.name should be(“Scooby Doo”)
d1.breed should be(“Doberman”)
There are safer alternatives for altering case classes:

case class Dog(name: String, breed: String) // Doberman

val d1 = Dog(“Scooby”, “Doberman”)

val d2 = d1.copy(name = “Scooby Doo”) // copy the case class but change the name in the copy

d1.name should be(“Scooby”) // original left alone
d1.breed should be(“Doberman”)

d2.name should be(“Scooby Doo”)
d2.breed should be(“Doberman”)
Case classes can have default and named parameters:

case class Person(first: String, last: String, age: Int = 0, ssn: String = “”)
val p1 = Person(“Fred”, “Jones”, 23, “111-22-3333”)
val p2 = Person(“Samantha”, “Jones”) // note missing age and ssn
val p3 = Person(last = “Jones”, first = “Fred”, ssn = “111-22-3333”) // note the order can change, and missing age
val p4 = p3.copy(age = 23)

p1.first should be(“Fred”)
p1.last should be(“Jones”)
p1.age should be(23)
p1.ssn should be(“111-22-3333”)

p2.first should be(“Samantha”)
p2.last should be(“Jones”)
p2.age should be(0)
p2.ssn should be(“”)

p3.first should be(“Fred”)
p3.last should be(“Jones”)
p3.age should be(0)
p3.ssn should be(“111-22-3333”)

(p1 == p4) should be(true)
Case classes can be disassembled to their constituent parts as a tuple:

case class Person(first: String, last: String, age: Int = 0, ssn: String = “”)
val p1 = Person(“Fred”, “Jones”, 23, “111-22-3333”)

val parts = Person.unapply(p1).get // this seems weird, but it’s critical to other features of Scala

parts._1 should be(“Fred”)
parts._2 should be(“Jones”)
parts._3 should be(23)
parts._4 should be(“111-22-3333”)

Case classes are Serializable

case class PersonCC(firstName: String, lastName: String)
val indy = PersonCC(“Indiana”, “Jones”)

indy.isInstanceOf[Serializable] should be(true)

class Person(firstName: String, lastName: String)
val junior = new Person(“Indiana”, “Jones”)

junior.isInstanceOf[Serializable] should be(false)

Scala Notes Section 1- 7

Option[A] is a container for an option value of type A. If the value of type A is present, the Option[A] is an instance of Some[A], containing the present value of A. If the value is absent , the Option[A] is the object of None.
Objects
An object is a singleton. One object, that’s it. This object is a replacement of static in Java, and is called upon much in the same way.
An object that has the same name as a class is called a companion object of the class, and it is often used to contain factory methods for the class that it complements
class Movie(val name: String, val year: Short)
object Movie {
def academyAwardBestMoviesForYear(x: Short) = {
//This is a match statement, more powerful than a Java switch statement!
x match {
case 1930 ⇒ Some(new Movie(“All Quiet On the Western Front”, 1930))
case 1931 ⇒ Some(new Movie(“Cimarron”, 1931))
case 1932 ⇒ Some(new Movie(“Grand Hotel”, 1932))
case _ ⇒ None
}
}
}
Movie.academyAwardBestMoviesForYear(1932).get.name should be()
A companion object can also see private values and variables of the corresponding classes’ instantiated objects
class Person(val name: String, private val superheroName: String) //The superhero name is private!
object Person {
def showMeInnerSecret(x: Person) = x.superheroName
}
val clark = new Person(“Clark Kent”, “Superman”)
val peter = new Person(“Peter Parker”, “Spiderman”)
val bruce = new Person(“Bruce Wayne”, “Batman”)
val diana = new Person(“Diana Prince”, “Wonder Woman”)
Person.showMeInnerSecret(clark) should be(“Superman”)
Tuples
Scala tuple combines a fixed number of items together so that they can be passed around as a whole. They are one indexed. Unlike an array or list, a tuple can hold objects with different types but they are also immutable. 
Tuples may be of mixed type: val tuple5 = (“a”, 1, 2.2, new Date(), “five”)
You can assign multiple variables at once using tuples:
val student = (“Sean Rogers”, 21, 3.5)
val (name, age, gpa) = student
Tuples items can be swapped on a Tuple 2: val tuple = (“apple”, 3).swap

HIGHER ORDER FUNCTIONS
Anonymous functions in source code are called function literals and at run time, function literals are instantiated into objects called function values.
Scala supports first-class functions, which means you can express functions in function literal syntax, i.e., (x: Int) => x + 1, and that functions can be represented by objects, which are called function values

def lambda = { x: Int ⇒ x + 1 }
def lambda2 = (x: Int) ⇒ x + 1
val lambda3 = (x: Int) ⇒ x + 1
val lambda4 = new Function1[Int, Int] {
def apply(v1: Int): Int = v1 + 1
}
def lambda5(x: Int) = x + 1
val result = lambda(3)
val result1andhalf = lambda.apply(3)
Closure:
var incrementer = 1
def closure = {
x: Int => x + incrementer
}
val result1 = closure(10)
Function returning another function using an anonymous function: def addWithSyntaxSugar(x: Int) = (y: Int) ⇒ x + y
Function taking another function as parameter. Helps in composing functions:
def makeUpper(xs: List[String]) = xs map {
_.toUpperCase
}
def makeWhatEverYouLike(xs: List[String], sideEffect: String ⇒ String) = {
xs map sideEffect
}

Lists
Scala Lists are quite similar to arrays which means, all the elements of a list have the same type but there are two important differences.
Fistr, lists are immutable, which means elements of a list cannot be changed by assignment.
Second, lists represent a linked list whereas arrays are flat. The type of a list that has elements of type T is written as List[T].

eq tests identity (same object)
== tests equality (same content)

val a = List(1, 2, 3)
val b = List(1, 2, 3)
(a eq b) should be(false)
(a == b) should be(true)

Nil lists are identical, even of different types
val a: List[String] = Nil
val b: List[Int] = Nil
(a == Nil) should be(true)
(a eq Nil) should be(true)
(b == Nil) should be(true)
(b eq Nil) should be(true)
(a == b) should be(true)
(a eq b) should be(true)

Lists can be accessed via head, headOption and tail. Accessing List via head is unsafe and may result in a IndexOutOfBoundsException
Lists have many useful methods
val a = List(1, 3, 5, 7, 9)

// get the length of the list
a.length should equal(5)
// reverse the list
a.reverse should equal(List(9,7,5,3,1))
// map a function to double the numbers over the list
a.map { v ⇒ v * 2 } should equal(List(2,6,10,14,18))
// filter any values divisible by 3 in the list
a.filter { v ⇒ v % 3 == 0 } should equal(List(3,9))

Lists can be reduced with a mathematical operation
val a = List(1, 3, 5, 7)
a.reduceLeft(_ + ) should equal(16)
a.reduceLeft(
* _) should equal(105)

val a = List(1, 3, 5, 7)
// NOTE: foldLeft uses a form called currying that we will explore later
a.foldLeft(0)(_ + ) should equal(16)
a.foldLeft(10)(
+ _) should equal(26)

You can create a list from a range
val a = (1 to 5).toList // List(1,2,3,4,5)
val b = (1 until 5).toList // List(1,2,3,4)

Maps
A Map is an Iterable consisting of pairs of keys and values (also named mappings or associations).
Scala’s Predef class offers an implicit conversion that lets you write key -> value as an alternate syntax for the pair (key, value). For instance Map(“x” -> 24, “y” -> 25, “z” -> 26) means exactly the same as Map((“x”, 24), (“y”, 25), (“z”, 26)), but reads better.
The fundamental operations on maps are similar to those on sets. They are summarized in the following table and fall into the following categories:
– Lookup operations apply, get, getOrElse, contains, and isDefinedAt. These turn maps into partial functions from keys to values. The fundamental lookup method for a map is: 
def get(key): Option[Value]. The operation “m get key” tests whether the map contains an association for the given key. If so, it returns the associated value in a Some. If no key is defined in the map, get returns None.
Maps also define an apply method that returns the value associated with a given key directly, without wrapping it in anOption. If the key is not defined in the map, an exception is raised.
Additions and updates +, ++, updated, which let you add new bindings to a map or change existing bindings. – Removals -, –, which remove bindings from a map.
Subcollection producerskeys, keySet, keysIterator, values, valuesIterator, which return a map’s keys and values separately in various forms. – Transformations filterKeys and mapValues, which produce a new map by filtering and transforming bindings of an existing map.

Maps contain distinct pairings:

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “MI” → “Michigan”)
myMap.size should be(3)
Maps can be added to easily:

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “MI” → “Michigan”)
val aNewMap = myMap + (“IL” → “Illinois”)
aNewMap.contains(“IL”) should be(true)

Map values can be iterated:

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “MI” → “Michigan”)

val mapValues = myMap.values // Iterable[String] = MapLike(Michigan, Ohio, Winsconsin)
mapValues.size should be(3)
mapValues.head should be(“Michigan”) //Failed presumption: The order in maps is not guaranteed

val lastElement = mapValues.last
lastElement should be(“Wisconsin”)

If a map key is requested using myMap(missingKey) which does not exist a NoSuchElementException will be thrown. Default values may be provided using either getOrElse or withDefaultValue for the entire map.

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”)
intercept[NoSuchElementException] {myMap(“TX”)}
myMap.getOrElse(“TX”, “missing data”) should be(“missing data”)

val myMap2 = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”) withDefaultValue “missing data”
myMap2(“TX”) should be(“missing data”)

Map elements can be removed easily:

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”)
val aNewMap = myMap – “MI”
aNewMap.contains(“MI”) should be(false)
myMap.contains(“MI”) should be(true)

Map elements can be removed in multiple/ a tuple

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”)
val aNewMap = myMap — List(“MI”, “OH”) OR
val aNewMap = myMap – (“MI”, “OH”)

aNewMap.contains(“MI”) should be(false)
myMap.contains(“MI”) should be(true)
aNewMap.contains(“WI”) should be(true)
aNewMap.size should be(2)
myMap.size should be(4)

Attempted removal of nonexistent elements from a map is handled gracefully:

val myMap = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”)
val aNewMap = myMap – “MN”

aNewMap.equals(myMap) should be(true)
Map equivalency is independent of order:

val myMap1 = Map(“MI” → “Michigan”, “OH” → “Ohio”, “WI” → “Wisconsin”, “IA” → “Iowa”)
val myMap2 = Map(“WI” → “Wisconsin”, “MI” → “Michigan”, “IA” → “Iowa”, “OH” → “Ohio”)

myMap1.equals(myMap2) should be(true)