Intro to pattern matching in scala

1,012 views

Published on

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

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,012
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
21
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Intro to pattern matching in scala

  1. 1. intro match { !case PatternMatching() !!!=> “Welcome” } Friday, September 6, 13
  2. 2. 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
  3. 3. Pattern Matching • A very powerful feature of Scala • Java’s “switch” on steroids? Friday, September 6, 13
  4. 4. 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
  5. 5. 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
  6. 6. 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
  7. 7. 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
  8. 8. Lets get on with it... Friday, September 6, 13
  9. 9. 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
  10. 10. 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
  11. 11. 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
  12. 12. Matching literals • A literal pattern L matches any value that is equal (in terms of ==) to the literal L. Friday, September 6, 13
  13. 13. matching strings def parseArgument(arg: String) = arg match { case "-h" | "--help" => displayHelp case "-v" | "--version" => displayVerion case whatever => unknownArgument(whatever) } Friday, September 6, 13
  14. 14. 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
  15. 15. 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
  16. 16. 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
  17. 17. 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
  18. 18. 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
  19. 19. variables • In general, everything in lowercase is treated as a “variable” • constants should start with uppercase Friday, September 6, 13
  20. 20. case matters class 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
  21. 21. case matters class 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? Compile error Friday, September 6, 13
  22. 22. case matters class 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? Compile error unreachable code Friday, September 6, 13
  23. 23. case matters class 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? Compile error unreachable code fix with: this.max Friday, September 6, 13
  24. 24. 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: scope Friday, September 6, 13
  25. 25. Matching List • List("Apple", "Microsoft") • List("Scala", "Clojure", "Groovy", _*) • "array explosion symbol" Friday, September 6, 13
  26. 26. look-alike Friday, September 6, 13
  27. 27. look-alike 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
  28. 28. 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
  29. 29. Guards • Powerful addition. • Allows for “conditional” matching Friday, September 6, 13
  30. 30. 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
  31. 31. More advanced topics? Quick breeze through Friday, September 6, 13
  32. 32. Nested patterns • case List(Cat(name), Owner(first, last)) Friday, September 6, 13
  33. 33. Nested - example object 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
  34. 34. 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
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. 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
  39. 39. Stable identifiers def f(x: Int, y: Int) = x match { case y => ... } def f(x: Int, y: Int) = x match { case `y` => ... } Friday, September 6, 13
  40. 40. 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
  41. 41. 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
  42. 42. Deconstructing BillVenners: 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
  43. 43. apply(...) / unapply(...) • And this is a whole new (albeit important) subject best left for next time... Friday, September 6, 13

×