Worksheet Algebraic Data Types and Pattern Matching
Table of Contents
1. Classes in Scala
1.1. Java Translation
Translate the following Java class definition into a corresponding Scala class definition.
You will need a companion object definition to model the static
components.
class Counter { private static int numCounters = 0; final int id; int count; Counter (int initial) { this.id = numCounters; this.count = initial; numCounters++; } static int getNumCounters () { return numCounters; } int getId () { return this.id; } int getNextCount () { return this.count++; } }
2. Algebraic Data Types via Case classes in Scala
2.1. MyList Case Class
Define your own MyList
class in Scala (as in the slides).
Now implement the following functions:
enum MyList[+X] { ... } import MyList._ def length [X] (xs:MyList[X]) : Int = { ... } def toList [X] (xs:MyList[X]) : List[X] = { ... } def fromList [X] (xs:List[X]) : MyList[X] = { ... } def append [X] (xs:MyList[X], ys:MyList[X]) : MyList[X] = { ... } def map [X,Y] (xs:MyList[X], f:X=>Y) : MyList[Y] = { ... }
2.2. Binary Tree Case Class
Define your own Tree
class for binary trees in Scala (as in the slides).
Now implement the following functions:
enum Tree[+X] { case Leaf case Node(l:Tree[X], c:X, r:Tree[X]) } import Tree.{Leaf,Node} val tree1:Tree[Int] = Leaf val tree2:Tree[Int] = Node (Leaf, 5, Leaf) val tree3:Tree[Int] = Node (Node (Leaf, 2, Leaf), 3, Node (Leaf, 4, Leaf)) // Find the size of a binary tree. Leaves have size zero here. def size [X] (t:Tree[X]) : Int = { ... } // Insert a number into a sorted binary tree. def insert [X] (x:X, t:Tree[X], lt:(X,X)=>Boolean) : Tree[X] = { ... } // Put the elements of the tree into a list using an in-order traversal. def inorder [X] (t:Tree[X]) : List[X] = { ... } def map [X,Y] (t:Tree[X], f:X=>Y) : Tree[Y] = { ... }
3. Solutions
3.1. Solution: Classes - Java Translation
object Counter: private var numCounters = 0 def getNumCounters : Int = numCounters def incNumCounters : Unit = numCounters = numCounters + 1 class Counter (initial:Int): private val id:Int = Counter.getNumCounters private var count:Int = initial Counter.incNumCounters def getId () : Int = id def getNextCount () : Int = { val tmp = count; count = count + 1; tmp }
3.2. Solution: MyList Case Class
enum MyList[+X]: case MyNil case MyCons(head:X, tail:MyList[X]) import MyList.* def length [X] (xs:MyList[X]) : Int = xs match case MyNil => 0 case MyCons (_, ys) => 1 + length (ys) def toList [X] (xs:MyList[X]) : List[X] = xs match case MyNil => Nil case MyCons (y, ys) => y::toList(ys) def fromList [X] (xs:List[X]) : MyList[X] = xs match case Nil => MyNil case y::ys => MyCons (y, fromList (ys)) def append [X] (xs:MyList[X], ys:MyList[X]) : MyList[X] = xs match case MyNil => ys case MyCons (z, zs) => MyCons (z, append (zs, ys)) def map [X,Y] (xs:MyList[X], f:X=>Y) : MyList[Y] = xs match case MyNil => MyNil case MyCons (y, ys) => MyCons (f (y), map (ys, f)) val xs = MyCons(11, MyCons(21, MyCons(31, MyNil))) val len = length (xs)
3.3. Solution: Binary Tree Case Class
import javax.swing.text.AbstractDocument.LeafElement enum Tree[+X]: case Leaf case Node(l:Tree[X], c:X, r:Tree[X]) import Tree.* val tree1:Tree[Int] = Leaf val tree2:Tree[Int] = Node (Leaf, 5, Leaf) val tree3:Tree[Int] = Node (Node (Leaf, 2, Leaf), 3, Node (Leaf, 4, Leaf)) // Find the size of a binary tree. Leaves have size zero here. def size [X] (t:Tree[X]) : Int = t match case Leaf => 0 case Node (t1, _, t2) => size (t1) + 1 + size (t2) // Insert a number into a sorted binary tree. def insert [X] (x:X, t:Tree[X], lt:(X,X)=>Boolean) : Tree[X] = t match case Leaf => Node (Leaf, x, Leaf) case Node (t1, c, t2) if (lt (x, c)) => Node (insert (x, t1, lt), c, t2) case Node (t1, c, t2) if (lt (c, x)) => Node (t1, c, insert (x, t2, lt)) case Node (t1, c, t2) => Node (t1, c, t2) // Put the elements of the tree into a list using an in-order traversal. def inorder [X] (t:Tree[X]) : List[X] = t match case Leaf => Nil case Node (t1, c, t2) => inorder (t1) ::: List (c) ::: inorder (t2) def map [X,Y] (t:Tree[X], f:X=>Y) : Tree[Y] = t match case Leaf => Leaf case Node (t1, c, t2) => Node (inorder (t1), f (c), inorder (t2))