imperative programming 2: pattern matching · •pattern matching is widely used in scala. • very...
TRANSCRIPT
![Page 1: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/1.jpg)
Imperative Programming 2: Pattern matching
Hongseok YangUniversity of Oxford
Monday, 29 April 13
![Page 2: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/2.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.Monday, 29 April 13
![Page 3: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/3.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
Monday, 29 April 13
![Page 4: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/4.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case class & inheri.instead of data types.2. match & case.
trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
Monday, 29 April 13
![Page 5: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/5.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case class & inheri.instead of data types.Match & case syntax.
trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
Monday, 29 April 13
![Page 6: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/6.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case class & inheri.instead of data types.Match & case syntax.
Monday, 29 April 13
![Page 7: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/7.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
sealed trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case class & inheri.instead of data types.Match & case syntax.
Sealed.Can define a custom pattern.Can match over types.
Monday, 29 April 13
![Page 8: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/8.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
sealed trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Tree): Int = t match { case Leaf(_) => 1 case SkewedTree(_) => 1 case Node(t1,t2) => count(t1) + count(t2) }
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case classesinstead of data types.Match & case syntax.
3
4
5 6
SkewedTree(List(3,4,5,6))
Sealed.Can define a custom pattern.Can match over types.
Monday, 29 April 13
![Page 9: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/9.jpg)
• Pattern matching is widely used in Scala.
• Very similar to pattern matching in Haskell.
• Of course, a few interesting differences exist.
trait Treecase class Node(l:Tree, r:Tree) extends Treecase class Leaf(v:Int) extends Tree
def count(t: Any): Int = t match { case Leaf(_) => 1 case SkewedTree(_) => 1 case Node(t1,t2) => count(t1) + count(t2) case _ : Int => 1 case _ => -1 }
data Tree = Node Tree Tree | Leaf Int
count :: Tree -> Intcount (Leaf _) = 1 count (Node l r) = count l + count r
Case classesinstead of data types.Match & case syntax.
Sealed.Can define a custom pattern.Can match over types.
Monday, 29 April 13
![Page 10: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/10.jpg)
Learning outcome
• Can explain the following features of Scala:
1. Case class.
2. Pattern matching.
3. Extractor.
• Can write interesting programs using these features.
Monday, 29 April 13
![Page 11: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/11.jpg)
Challenge 1 :Arithmetic expression
• Represent arithmetic expressions in Scala:
(7.0 * x3) + (3.8 * -y), (x + y) / 5.0
• Implement a function that simplifies an expression using the following equalities:
-(-e) = e e * 1 = e e + 0 = e
Monday, 29 April 13
![Page 12: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/12.jpg)
Plan
1. Represent different types of expressions using case classes and inheritance.
• A common idiom in Scala for implementing an algebraic data type (such as tree and list etc).
2. Implement simplification by pattern matching.
Monday, 29 April 13
![Page 13: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/13.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = ... expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))simplify(e2)
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
Monday, 29 April 13
![Page 14: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/14.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = ... expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))simplify(e2)
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.Subtyping allows us to treat objects of all four classes as expressions.
Monday, 29 April 13
![Page 15: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/15.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = ... expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}val e = new BOp(“*“, new UOp(“-“, new UOp(“-“, new Num(0.0))), new Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.Objects can be constructed without new. Class names can be used as patterns..
Monday, 29 April 13
![Page 16: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/16.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = ... expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.Objects can be constructed without new. Class names can be used as patterns..
Monday, 29 April 13
![Page 17: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/17.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => ... ... ... ... case BOp(op, l, r) => ... case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.Objects can be constructed without new. Class names can be used as patterns..
Monday, 29 April 13
![Page 18: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/18.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) ... ... ... case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
Monday, 29 April 13
![Page 19: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/19.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) ... ... ... case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
[Q1] Implement simplification for e*1=e and e+0=e. Monday, 29 April 13
![Page 20: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/20.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
[Q1] Implement simplification for e*1=e and e+0=e. Monday, 29 April 13
![Page 21: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/21.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
[Q2] Add a new simplification case for e+e = 2*e.Monday, 29 April 13
![Page 22: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/22.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“+“, x, y) if x==y => BOp(“*“, Num(2), simplify(x)) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
1. Represent different types of expressions using case classes and inheritance.
2. Implement simplification by pattern matching.
[Q2] Add a new simplification case for e+e = 2*eMonday, 29 April 13
![Page 23: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/23.jpg)
match statement
selector match { case pattern1 => instruction1 case pattern2 => instruction2 ... case patternk => instructionk}
Some possible patterns: 2 UOp(“-“, UOp(“-“, x)) (x:Var) BOp(“+“,x,y) if x==y
More patterns are described in the textbook (Chap 15).
Monday, 29 April 13
![Page 24: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/24.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
Challenge 2 :Hide representation of Exp
Monday, 29 April 13
![Page 25: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/25.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
Bob
Challenge 2 :Hide representation of ExpAlice
Monday, 29 April 13
![Page 26: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/26.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp, prec: Int) extends Exp
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) case BOp(“+“, e, Num(0.0)) => simplify(e) case BOp(“*“, e, Num(1.0)) => simplify(e) case UOp(op, e) => UOp(op, simplify(e)) case BOp(op, l, r) => BOp(op, simplify(l), simplify(r)) case _ => expr}
val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
Bob
Alice
Bob’s code will not work after Alice’s change.
Challenge 2 :Hide representation of Exp
Monday, 29 April 13
![Page 27: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/27.jpg)
Idea
Bob is using names of case classes only in two ways:
1. Factory method for creating an object.
2. Pattern in pattern matching.
Idea : Write custom factory methods and patterns, and export them, but not classes.
def simplify(expr: Exp): Exp = expr match { case UOp(“-“, UOp(“-“, e)) => simplify(e) ...}val e = BOp(“*“, UOp(“-“, UOp(“-“, Num(0.0))), Num(1.0))
Monday, 29 April 13
![Page 28: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/28.jpg)
• Option[C] is a new type that includes all values of type C and None.
• Values of an option type are typically constructed by a function that works for only some, not all inputs.
• Normally, they get destructed by pattern matching.
def mySqrt(x: Double): Option[Double] = if (x >= 0.0) Some(math.sqrt(x)) else None
def show(x: Option[Double]) = x match { case Some(v) => println(v) case None => println(“?“) }
val x: Option[Double] = Some(3.2)val y: Option[Double] = None
Option type
Monday, 29 April 13
![Page 29: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/29.jpg)
Understanding case class• The compiler generates factory method and pattern
for each case class.
• They are apply and unapply methods in the companion object, which is also generated by the compiler. case class BOp(op: String, left: Exp, right: Exp) extends Exp
object BOp ... { def apply(op: String, left: Exp, right: Exp): BOp = ... def unapply(bop: Any): Option[(String, Exp, Exp)] = ...}
Monday, 29 April 13
![Page 30: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/30.jpg)
Understanding case class• The compiler generates factory method and pattern
for each case class.
• They are apply and unapply methods in the companion object, which is also generated by the compiler. case class BOp(op: String, left: Exp, right: Exp) extends Exp
object BOp ... { def apply(op: String, left: Exp, right: Exp): BOp = ... def unapply(bop: Any): Option[(String, Exp, Exp)] = ...}
val e=BOp(“*“, Num(1.0), Num(1.0))
Monday, 29 April 13
![Page 31: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/31.jpg)
Understanding case class• The compiler generates constructor (factory method)
and destructor for each case class.
• They are apply and unapply methods in the companion object, which is also generated by the compiler. case class BOp(op: String, left: Exp, right: Exp) extends Exp
object BOp ... { def apply(op: String, left: Exp, right: Exp): BOp = ... def unapply(bop: Any): Option[(String, Exp, Exp)] = ...}
expr match { case BOp(“+“, _, _) => ... case _ => ...}
val e=BOp(“*“, Num(1.0), Num(1.0))
Monday, 29 April 13
![Page 32: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/32.jpg)
Recipe for building custom factory method and pattern
• Declare a singleton object T.
• Define apply & unapply methods in the object T.
• Now we have a factory method T(...) and a pattern T(...).
• Good practice : unapply is the inverse of apply.
• A singleton object with unapply is called extractor.
Monday, 29 April 13
![Page 33: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/33.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
original representation
1. Declare a singleton object T.
2. Define apply & unapply methods in the object T.
Monday, 29 April 13
![Page 34: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/34.jpg)
sealed trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { // extractor private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(name) def unapply(e: Exp): Some[String] = e match { case e1: Var => e.name case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
Monday, 29 April 13
![Page 35: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/35.jpg)
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { // extractor private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Exp): Some[String] = e match { case e1: Var => e.name case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
Monday, 29 April 13
![Page 36: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/36.jpg)
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { // extractor private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Any): Option[String] = e match { case e1: Var => Some(e1.name) case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
Monday, 29 April 13
![Page 37: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/37.jpg)
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { // extractor private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Any): Option[String] = e match { case e1: Var => Some(e1.name) case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
Compiler-generated code for the case class Var:object Var ... { ... def apply(n: String): Var = new Var(n) def unapply(e: Any): Option[String] = ...}
Monday, 29 April 13
![Page 38: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/38.jpg)
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { // extractor private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Any): Option[String] = e match { case e1: Var => Some(e1.name) case _ => None }}
original representation
new representation[Q] Do the same thing for BOp,
and hide its implementation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
Monday, 29 April 13
![Page 39: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/39.jpg)
[Q] Do the same thing for BOp, and hide its implementation
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Exp): Some[String] = e match { case e1: Var => Some(e1.name) case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
object BOp { // extractor private class BOp(val op:String, val l:Exp, val r:Exp) extends Exp def apply(op:String, l:Exp, r:Exp): Exp = new BOp(op,l,r) def unapply(e: Any): Option[(String, Exp, Exp)] = e match { case e1: BOp => Some((e1.op, e1.l, e1.r)) case _ => None }}
Monday, 29 April 13
![Page 40: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/40.jpg)
[Q] Do the same thing for BOp, and hide its implementation
trait Expcase class Var(name: String) extends Expcase class Num(num: Double) extends Expcase class UOp(op: String, arg: Exp) extends Expcase class BOp(op: String, left: Exp, right: Exp) extends Exp
trait Expobject Var { private class Var(val name: String) extends Exp def apply(n: String): Exp = new Var(n) def unapply(e: Exp): Some[String] = e match { case e1: Var => Some(e1.name) case _ => None }}
original representation
new representation
1. Declare a singleton object T.
2. Define apply & unapply methods to the object T.
object BOp { // extractor private class BOp(val op:String, val l:Exp, val r:Exp, val prec:Int) extends Exp def apply(op:String, l:Exp, r:Exp): Exp = new BOp(op,l,r,0) def unapply(e: Any): Option[(String, Exp, Exp)] = e match { case e1: BOp => Some((e1.op, e1.l, e1.r)) case _ => None }}
Monday, 29 April 13
![Page 41: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/41.jpg)
Challenge 3: Email address• Email addresses are strings of the form:
string@string
• We would like to use patterns for email addresses:
• [Q] Complete the definition of the EMail object:
def printEMail(s: String) { s match { case EMail(user, domain) => println(user +“ AT “+ domain) case _ => println(“not an email address“) }}
Monday, 29 April 13
![Page 42: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/42.jpg)
Challenge 3: Email address• Email addresses are strings of the form:
string@string
• We would like to use patterns for email addresses:
• Complete the definition of the extractor EMail:
def printEMail(s: String) { s match { case EMail(user, domain) => println(user +“ AT “+ domain) case _ => println(“not an email address“) }}
object EMail { def apply(user: String, domain: String) = user +“@“+ domain def unapply(s: String): Option[(String, String)] = ... val parts = s.split(“@“) if (parts.length == 2) Some(parts(0), parts(1)) else None }} Hint: “a@b@c“.split(“@“) = List(“a“,“b“,“c“)
Monday, 29 April 13
![Page 43: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/43.jpg)
Challenge 3: Email address• Email addresses are strings of the form:
string@string
• We would like to use patterns for email addresses:
• Complete the definition of the extractor EMail:
def printEMail(s: String) { s match { case EMail(user, domain) => println(user +“ AT “+ domain) case _ => println(“not an email address“) }}
object EMail { def apply(user: String, domain: String) = user +“@“+ domain def unapply(s: String): Option[(String, String)] = { val parts = s.split(“@“) if (parts.length == 2) Some(parts(0), parts(1)) else None }}
EMail implements an alternative view on certain strings.
Monday, 29 April 13
![Page 44: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/44.jpg)
Extractor
• A singleton object that contains the unapply method.
• It can be used as a pattern in pattern matching.
• Two usages seen today:
• Information hiding.
• An alternative view on data.
Monday, 29 April 13
![Page 45: Imperative Programming 2: Pattern matching · •Pattern matching is widely used in Scala. • Very similar to pattern matching in Haskell. • Of course, a few interesting differences](https://reader034.vdocuments.net/reader034/viewer/2022042922/5f6c96f1cdf2b406961bb709/html5/thumbnails/45.jpg)
Summary
• Key concepts covered:
• Pattern matching.
• Case class.
• apply (factory method) and unapply (pattern).
• Extractor.
• Read Chap 15 and Chap 26.1 - 26.3
Monday, 29 April 13