intro to pattern matching in scala

43
intro match { case PatternMatching() => Welcome} Friday, September 6, 13

Upload: jan-krag

Post on 27-May-2015

413 views

Category:

Technology


1 download

DESCRIPTION

Slide deck used for a presentation i gave at CPH Scala Group meeting, Oct. 5th, 2013 in Copenhagen.

TRANSCRIPT

Page 1: Intro to pattern matching in scala

intro match {!case PatternMatching()!!!=> “Welcome”}

Friday, September 6, 13

Page 2: Intro to pattern matching in scala

Who am I?

• Java & Scala developer at Schantz A/S

•Polyglot curious, Coursera junkie

• Interested in HCI and Usability

•https://github.com/JKrag

@jankrag

• Geek, builder and flyer of kites, reptile & cat breeder, Rubik's puzzle fan

Friday, September 6, 13

Page 3: Intro to pattern matching in scala

Pattern Matching

• A very powerful feature of Scala

• Java’s “switch” on steroids?

Friday, September 6, 13

Page 4: Intro to pattern matching in scala

Java’s switch

• lets you match a ‘value’ agains a number of cases, and conditionally executes code

• basically only switch on numeric values

• int, byte, etc....

• (Yes, Java 7 has switch on String, but only syntactic sugar.)

• Performance > nested if ’s

Friday, September 6, 13

Page 5: Intro to pattern matching in scala

Scala’s ‘match’

• Lets you match a ‘value’ agains complex patterns

• Can switch on multiple types

• Can match most kind of types by matching agains the “creation form” of an object (patience...)

Friday, September 6, 13

Page 6: Intro to pattern matching in scala

Scala’s match (cont.)

• Each “case” is a Scala expression, and thus Each “match” block is an expression

• Can be used as a full function body...

Friday, September 6, 13

Page 7: Intro to pattern matching in scala

History

• Pattern matching is nothing new

• Has existed way back in functional languages

• Most notable early example: ML

• Also found in Haskell, Erlang, OCaml etc.

Friday, September 6, 13

Page 8: Intro to pattern matching in scala

Lets get on with it...

Friday, September 6, 13

Page 9: Intro to pattern matching in scala

Syntax - simple “java like”

def weather(code: Int): String = { code match { case 1 => "sun" case 0 => "rain" case _ => "error" }}

“_” is used as wildcard for the “default” case, when we don’t need the matched value...

Friday, September 6, 13

Page 10: Intro to pattern matching in scala

Syntax

def weather(code: Int) = code match { case 1 => "sun" case 0 => "rain" case _ => "error"}

match used directly as full function body

Friday, September 6, 13

Page 11: Intro to pattern matching in scala

multiple matches

def myPlans(weekday: Int) = weekday match {! case 1 | 2 | 3 | 4 | 5 => "work"! case 6 | 7 => "relax"! case _ => "unknown weekday"}

Friday, September 6, 13

Page 12: Intro to pattern matching in scala

Matching literals

• A literal pattern L matches any value that is equal (in terms of ==) to the literal L.

Friday, September 6, 13

Page 13: Intro to pattern matching in scala

matching strings

def parseArgument(arg: String) = arg match { case "-h" | "--help" => displayHelp case "-v" | "--version" => displayVerion case whatever => unknownArgument(whatever)}

Friday, September 6, 13

Page 14: Intro to pattern matching in scala

Mixed stuff

def handle(msg: Any) = msg match {! "QUIT" => "recieved stop request"! 42 => "The answer to the ultimate question"! _ => "something else"}

Friday, September 6, 13

Page 15: Intro to pattern matching in scala

matching tuples

def moveTo(coord: Any) = coord match {! case (_, _) => println("received good 2D coord.")! case (_, _ , _) => println("3D not supported")! case _ => println("unexpected stuff")}

Friday, September 6, 13

Page 16: Intro to pattern matching in scala

matching on types

• In java, if you need to “detect” types, you typically use “instance of” and typecast

• In scala, we can match on types, using variables, and these know the type

Friday, September 6, 13

Page 17: Intro to pattern matching in scala

types and variables

def handle(msg: Any) = msg match { case i:Int => "Int'eresting: " + i case _:Double => "Doubly so!" case s:String => "You really want't me to do " + s}

• introduced variables (typed of course)• order can be important. Cases checked in order

Friday, September 6, 13

Page 18: Intro to pattern matching in scala

matching tuples - revisited

def moveTo(coord: Any) = coord match {! case (a: Int, b: Int) => updateCoordinate(a, b)! case (_, _ , _) => println("3D not supported")! case _ => println("unexpected coordinate")}

Friday, September 6, 13

Page 19: Intro to pattern matching in scala

variables

• In general, everything in lowercase is treated as a “variable”

• constants should start with uppercase

Friday, September 6, 13

Page 20: Intro to pattern matching in scala

case mattersclass Sample {

! val max = 100! val MIN = 0! def process(input: Int) {! ! input match {! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN")! ! ! case _ => println("unreachable")! ! }! }}

What happens?

Friday, September 6, 13

Page 21: Intro to pattern matching in scala

case mattersclass Sample {

! val max = 100! val MIN = 0! def process(input: Int) {! ! input match {! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN")! ! ! case _ => println("unreachable")! ! }! }}

What happens?Com

pile err

or

Friday, September 6, 13

Page 22: Intro to pattern matching in scala

case mattersclass Sample {

! val max = 100! val MIN = 0! def process(input: Int) {! ! input match {! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN")! ! ! case _ => println("unreachable")! ! }! }}

What happens?Com

pile err

or

unreachable code

Friday, September 6, 13

Page 23: Intro to pattern matching in scala

case mattersclass Sample {

! val max = 100! val MIN = 0! def process(input: Int) {! ! input match {! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN")! ! ! case _ => println("unreachable")! ! }! }}

What happens?Com

pile err

or

unreachable codefix with: this.max

Friday, September 6, 13

Page 24: Intro to pattern matching in scala

Practical example:Recursive factorial

• Without pattern matching:def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1)

• With pattern matching:def fact(n: Int): Int = n match { case 0 => 1 case n => n * fact(n - 1)}

• Note: n matches “everything else”

• Note: scopeFriday, September 6, 13

Page 25: Intro to pattern matching in scala

Matching List

• List("Apple", "Microsoft")

• List("Scala", "Clojure", "Groovy", _*)

• "array explosion symbol"

Friday, September 6, 13

Page 26: Intro to pattern matching in scala

look-alike

Friday, September 6, 13

Page 27: Intro to pattern matching in scala

look-alikelist match { ! ! case Nil => "was an empty list" !! case x :: xs => "head was " + x + ", tail was " + xs}

//remember a list in scala is either Nil, or “something and a tail”

Friday, September 6, 13

Page 28: Intro to pattern matching in scala

look-alike

def length[A](list : List[A]) : Int = list match { case _ :: tail => 1 + length(tail) case Nil => 0}

list match { ! ! case Nil => "was an empty list" !! case x :: xs => "head was " + x + ", tail was " + xs}

//remember a list in scala is either Nil, or “something and a tail”

Friday, September 6, 13

Page 29: Intro to pattern matching in scala

Guards

• Powerful addition.

• Allows for “conditional” matching

Friday, September 6, 13

Page 30: Intro to pattern matching in scala

Guards - example

case msg : Int if (msg < 0) => printf("Execution problem. Return code: %d")

case msg : Int if (msg > 0) => printf("Succes. Return code: %d")

case _ : Int => printf("Boring")

Friday, September 6, 13

Page 31: Intro to pattern matching in scala

More advanced topics?Quick breeze through

Friday, September 6, 13

Page 32: Intro to pattern matching in scala

Nested patterns

• case List(Cat(name), Owner(first, last))

Friday, September 6, 13

Page 33: Intro to pattern matching in scala

Nested - exampleobject Role extends Enumeration {

! type Role = Value! val DEV, PM, CEO = Value}case class Name(first:String, last:String)case class Person(name:Name, age:Int, role:Role)

val person = Person(Name("Jan", "Krag"), 42, Role.DEV)

person match {! case Person(Name(first, last), age:Int, r: Role) => first + " " + last + " (aged " + age + ")"! case _ => "something else"} //> res4: java.lang.String = "Jan Krag (aged 42) "

Friday, September 6, 13

Page 34: Intro to pattern matching in scala

Pattern binders

• We can assign a binder to part of a pattern during a match using the @ notation.

• Often usefull when we want a larger part of a pattern to use on the expression side

• e.g. case pers @ Person(“Dude”, _, _) => println(pers)

• binds pers to the whole Person object

Friday, September 6, 13

Page 35: Intro to pattern matching in scala

Regular expressions

val Name = """(\w+)\s+(\w+)""".r"Jan Krag" match { case Name(first,last) => println("found: ", first, last) case _ => println("oh no!")}

(found: ,Jan,Krag)

Friday, September 6, 13

Page 36: Intro to pattern matching in scala

case classes

• Very common use case

• If case class is sealed abstract, compiler can verify that match is exhaustive

• works because case classes have an auto-generated unapply method.

Friday, September 6, 13

Page 37: Intro to pattern matching in scala

exhaustive match

sealed abstract class Expr case class Var(name: String) extends Expr case class Number(num: Double) extends Expr case class UnOp(operator: String, arg: Expr) extends Expr case class BinOp(operator: String, left: Expr, right: Expr) extends Expr

def describe(e: Expr): String = e match { case Number(_) => "a number" case Var(_) => "a variable" } //warning: match is not exhaustive! //missing combination UnOp //missing combination BinOp

Friday, September 6, 13

Page 38: Intro to pattern matching in scala

Matching XML fragments

• As Scala has first class support for XML, we can also match XML fragments:

case <price>{itemPrice}</price> => println("price was: " + itemPrice)

Friday, September 6, 13

Page 39: Intro to pattern matching in scala

Stable identifiersdef f(x: Int, y: Int) = x match {

case y => ...}

def f(x: Int, y: Int) = x match { case `y` => ...}

Friday, September 6, 13

Page 40: Intro to pattern matching in scala

anomymous functions

• case classes can also be used as anonymous functions, i..e. without a “match” clause:

• { case p1 => b1 ... case pn => bn }

Friday, September 6, 13

Page 41: Intro to pattern matching in scala

in Exception handling

try { throw new j.i.IOException("no such file")} catch { case e @ (_ : RuntimeException | _ : j.i.IOException) => println(e)}

// prints out "java.io.IOException: no such file"

Example also demonstrates binding of “alternatives” expression

Friday, September 6, 13

Page 42: Intro to pattern matching in scala

Deconstructing Bill Venners: You said a pattern looks like an expression, but it seems kind of like a backwards expression. Instead of plugging values in and getting one result out, you put in one value, and when it matches, a bunch of values pop back out.

Martin Odersky: Yes. It's really the exact reversal of construction. I can construct objects with nested constructors, and maybe I also have some parameters. Let's say I have a method that takes some parameters and constructs some complicated object structure from those parameters. Pattern matching does the reverse. It takes a complicated object structure and pulls out the parameters that were used to construct the same structure.

Friday, September 6, 13

Page 43: Intro to pattern matching in scala

apply(...) / unapply(...)

• And this is a whole new (albeit important) subject best left for next time...

Friday, September 6, 13