Pattern matching. The if expression The else part of an if expression is optional if ( condition )...

20
Pattern matching

Transcript of Pattern matching. The if expression The else part of an if expression is optional if ( condition )...

Page 1: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Pattern matching

Page 2: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

The if expression

The else part of an if expression is optional if (condition) expression1 else expression2

If the condition evaluates to true, the value of the if-expression is expression1, else it is expression2

if (condition) expression1 If the condition evaluates to true, the value of the if-expression is

expression1, else it is “unit” Regardless of the type of expression1, the type of the result is Any

Scala determines the type of everything before the program runs, and at that time it doesn’t know whether the condition will be true

When you use an if without an else, typically you don’t care what the value of the if-expression will be

2

Page 3: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Unit-returning expressions In Scala, the “statements” are really expressions But a lot of expressions return Unit, ()

for (without yield) while assignments val and var print and println methods

Some expressions (can) return more meaningful values if, especially with else

Without else, if you don’t get Unit, you get a value of type Any for with yield The match method Arithmetic, logical, or string expressions Your own methods

3

Page 4: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Dealing with Any Any usually means that Scala doesn’t know the type

Scala determines types at compile time; if the type depends on what happens at run time, Scala can’t know exactly

scala> val x = if (true) "abc"x: Any = abc

scala> x.toStringres1: String = abc

scala> val y = if (true) 123y: AnyVal = 123

scala> y.toInt<console>:9: error: value toInt is not a member of AnyVal y.toInt ^

scala> y.toString.toIntres3: Int = 123

4

Page 5: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

The match expression

The match expression is more general than if The syntax is: expression match { case value1 => result1

case value2 => result2

. . . case valueN => resultN

} The expression is evaluated, then compared with each value in order

When a value is found that matches the expression, the corresponding result is computed, and that is the value of the match expression

5

Page 6: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Example match expressions Boolean-expression match {

case true => expression1

case false => expression2

}is equivalent toif (Boolean-expression) expression1 else expression2

def describe(x: Any): String = x match { case 5 => "five" case true => "truth" case "hello" => "hi!" case Nil => "The empty list" case _ => "something else" // _ will match anything}

This example taken from Programming in Scala, 2nd ed., p. 275

6

Page 7: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

match with variables You can use case variable =>

The match will succeed, and the variable will get the value of the expression being matched

scala> val n = 5n: Int = 5

scala> n match { | case 1 => 10 | case x => 10 * x | }res6: Int = 50

In the above, x gets, as a val, the value of the expression n You don’t explicitly say val x, just say x

The scope of x is just the case in which it occurs; you cannot use it after the match expression

7

Page 8: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

match with sequences

You can match a sequence (List, Vector, Array,…) scala> val nums = List(10, 20, 30, 40)

nums: List[Int] = List(10, 20, 30, 40)

scala> nums match { | case List(a, b, c, d) => println(s"a is $a, d is $d") | }a is 10, d is 40

You can use underscore as a wild card, meaning “match and forget”

scala> nums match { | case List(_, b, _, _) => println(s"b is $b") | }b is 20

Unlike an ordinary variable, _ can match something different each time

8

Page 9: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

The extended wildcard, _* _* will match all remaining elements (zero or more of them)

scala> def take3(v: Vector[Int]) = v match { | case Vector(a, b, c, _*) => | println("No problem!") | Vector(a, b, c) | case _ => | println("I can't take three!") | v :+ 99 | }take3: (v: Vector[Int])scala.collection.immutable.Vector[Int]

scala> take3(Vector(11, 22, 33, 44, 55, 66))No problem!res26: scala.collection.immutable.Vector[Int] = Vector(11, 22, 33)

scala> take3(Vector(11, 22))I can't take three!res27: scala.collection.immutable.Vector[Int] = Vector(11, 22, 99)

Braces, { }, are not needed to have multiple expressions in a case9

Page 10: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Pattern matching in assignments

scala> val Vector(x, y) = Vector(101, 102)x: Int = 101y: Int = 102

scala> val Vector(a, b, c, _*) = Vector(11, 22, 33, 44)a: Int = 11b: Int = 22c: Int = 33

scala> var List(p, q, r) = List("one", "two", "three")p: String = oneq: String = twor: String = three

10

Page 11: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

match with types scala> def printType(x: Any) = x match {

| case d: Double => println(s"$d is a Double") | case i: Int => println(s"$i is an Int") | case s: String => println(s"$s is a String") | case other => println(s"I don't know what $other is!") | }printType: (x: Any)Unit

scala> printType(5.3)5.3 is a Double

scala> printType("abc")abc is a String

scala> printType('a')I don't know what a is!

11

Page 12: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

No match with generic types scala> def printType(x: List[Any]) {

| x match { | case n: List[Int] => println("These are Ints") | case n: List[String] => println("These are Strings") | } | }<console>:13: warning: non-variable type argument Int in type pattern List[Int] is unchecked since it is eliminated by erasure case n: List[Int] => println("These are Ints") ^<console>:14: warning: non-variable type argument String in type pattern List[String] is unchecked since it is eliminated by erasure case n: List[String] => println("These are Strings") ^<console>:14: warning: unreachable code case n: List[String] => println("These are Strings") ^printType: (x: List[Any])Unit

scala> printType(List("a"))These are Ints

12

Page 13: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Tuples

A tuple is a sequence of values enclosed in parentheses The values may be of different types scala> val t = (1, "abc", 5.3)t: (Int, String, Double) = (1,abc,5.3)

Notice how the type is expressed: (Int, String, Double) Tuples may be assigned to tuples

scala> val (x, y, z) = tx: Int = 1y: String = abcz: Double = 5.3

Components of a tuple are accessed with ._1, ._2, ._3, etc. scala> println(s"t._1 is ${t._1} and t._3 is ${t._3}")t._1 is 1 and t._3 is 5.3

13

Page 14: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Pattern matching on tuples

scala> val card = (12, "Spades")card: (Int, String) = (12,Spades)

scala> ( card match { | case (1, _) => "Ace of " | case (11, _) => "Jack of " | case(12, _) => "Queen of " | case(13, _) => "King of " | } ) + card._2res3: String = Queen of Spades

14

Page 15: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Option

Just as a Vector can hold zero or more items, an Option can hold zero or one item If it holds zero items, its value is None If it holds item, its value is Some(item)

Option is perfect when you don’t know whether or not you are going to have a value

Typical uses: Searching for something in a Vector or a List Trying to solve a problem that may not have a solution (or

at least, not one you can find) You can match on Some(variable) or None

15

Page 16: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Using Option in a search method scala> val names = List("Bob", "Alice", "Charles", "Dawn")

names: List[String] = List(Bob, Alice, Charles, Dawn)

scala> def find(name: String, names: List[String]): Option[Int] = { | var result: Option[Int] = None | for (i <- 0 until names.length if result == None) { | if (name == names(i)) result = Some(i) | } | result | }find: (name: String, names: List[String])Option[Int]

scala> find("Alice", names)res4: Option[Int] = Some(1)

scala> find("dawn", names)res5: Option[Int] = None

16

Page 17: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

Pattern matching with Option scala> find("Charles", names) match {

| case Some(x) => println(s"Found at location $x") | case None => println("Nobody here by that name!") | }Found at location 2

As mentioned before, you can do pattern matching in assignments scala> val Some(loc) = find("Charles", names)loc: Int = 2

…But it’s dangerous, and not recommended scala> val Some(loc2) = find("Inigo", names)scala.MatchError: None (of class scala.None$)

17

Page 18: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

match with guards scala> def describe(x: Int) = x match {

| case n if n < 0 => s"$n is negative" | case n if n == 0 => "That's a zero" | case n if n % 2 == 0 => s"$n is an even number" | case n if n % 2 != 0 => s"$n is an odd number" | case _ => "How did I get here?" | }describe: (x: Int)String

scala> describe(3)res34: String = 3 is an odd number

scala> describe(-3)res35: String = -3 is negative

18

Page 19: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

patterns in for expressions scala> val students = List(("Mary", 95), ("John",

46), ("Bill", 75))students: List[(String, Int)] = List((Mary,95), (John,46), (Bill,75))

scala> for ((name, score) <- students) { | if (score >= 70) println(s"$name did well.") | else println(s"$name did poorly.") | }Mary did well.John did poorly.Bill did well.

19

Page 20: Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.

The End