case classesval)- case class C (x:Int, y:String)
- val c:C = C (5, "hello")
- val a:Int = c.x
- c.x = 6 // error: reassignment to val
toString implementationapply method
unapply method / extractors in textbookenum lists disjoint alternatives- enum Color:
- case Blue
- case White
- enum Expr:
- case Number(x: Int)
- case Plus(l: Expr, r: Expr)
- ...
Create instances
- val b = Color.Blue
- import Expr.*
- val three = Number(3)
- val plus = Plus(three, Number(5))
- def eval(e: Expr) : Int = e match
- case Number(x) => x
- case Plus(l, r) => eval(l) + eval(r)
- ...
- end eval
eval- // (3+5)*2
- val v = Times(Plus(Number(3), Number(5)), Number(2))
- val i: Int = eval(v) // i==16
Which "states" does a list have which case classes and case objects?
Empty list and a Cons cell of at least one element- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
Create an empty list?
Simply use Empty
- import MyList.*
- val xs = Empty
Create an instance of a list?
Nest Cons and terminate with Empty
- import MyList.*
- val xs = Cons (1, Cons(2, Cons(3, Empty)))
- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
- object MyList:
- def create(elems: Int*) : MyList =
- if elems.isEmpty then Empty
- else Cons(elems.head, create(elems.tail*))
Create an instance of a list?
Use method create
- import MyList.*
- // val xs = Cons (1, Cons(2, Cons(3, Empty)))
- val xs = MyList.create(1, 2, 3)
Generalize to any element type?
- enum MyList[+X]:
- case Empty
- case Cons (head:X, tail:MyList[X])
Compute the length of such a list?
- def length [X] (xs:MyList[X]): Int = xs match
- case MyList.Empty => 0
- case MyList.Cons(a,as) => 1 + length(as)
Algebraic data types: sum of products
Product types
- val product = (1, "hello", List(1, 2, 3))
Sum types
- class A; class B extends A; class C extends A
enum and case classes- enum Sum:
- case Product1(i: Int, s: String)
- case Product2(i: Int, j: Int, k: Int)
- ...
PeanoNat- enum PeanoNat:
- case Zero
- case Succ(n: PeanoNat)
PeanoNat to Int- import PeanoNat.*
- def peano2int (p: PeanoNat, result: Int = 0): Int = p match
- case Zero => result
- case Succ(n) => peano2int (n, result+1) // tail-recursive
- val q = Succ(Succ(Succ(Zero))) // val q: Peano = ...
- peano2int(q) // : Int = 3
- enum Tree[X]:
- case Leaf (data:X)
- case Node (l:Tree[X], f:(X,X)=>X, r:Tree[X])
- def fold [X] (t: Tree[X]) : X = t match
- case Leaf(x) => x
- case Node(l, f, r) => f(fold(l), fold(r))
# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-dumbbell fa-stack-1x fa-inverse"></i></span> Pattern Matching with Complex Datatypes <div class="grid grid-cols-2 gap-4"> <div> - Recursively traverse a data structure (recall [Formal Semantics](https://reed.cs.depaul.edu/efredericks/csc447/slides/html/07-formalsemantics.html#8)) ```scala abstract class Expr class Number(val x: Int) extends Expr class Plus(val l: Expr, val r: Expr) extends Expr ... ``` * Evaluate an expression ```scala def eval(e: Expr) : Int = e match case n: Number => n.x case n: Plus => eval(n.l) + eval(n.r) ... end eval ``` </div> <div> * :fa fa-circle-question: What if `Number(...)` and `Plus(...)` were l-values? ```scala def eval(e: Expr) : Int = e match case Number(x) => x case Plus(l, r) => eval(l) + eval(r) ... end eval ``` * Scala `enum` to express algebraic data types </div> </div> ---