===== 5. Functional data representation in Scala ====== /* (Functional) Data representation in Scala A few syntax basics: */ // we define a class (called Point) // we define the constructor for the class: // Point(1,2) class Point(x: Int, y: Int){ def xVal:Int = x def yVal:Int = y // checks if a point is higher on the y axis than our current point // higher is method of the class Point def higher(p: Point): Boolean = p.yVal > y override def toString : String = s"({$x},{$y})" } val p = new Point(1,2) p.higher(new Point(2,3)) new Point(2,1) // this is an expression that evaluates to an object new Point(2,1) == new Point(2,1) // evaluates to FALSE // classes in Scala are VERY similar to those in Java /* Traits in Scala are VERY similar to Java interfaces */ trait FTree { /* why do we not define methods, such as isEmpty and size as MEMBERS of FTree? is it possible? (YES) */ } case object FEmpty extends FTree {} case class FNode(key: Int, left: FTree, right: FTree) extends FTree {} FEmpty == FEmpty // should return true val t1 = FNode(7, FNode(1,FEmpty,FEmpty), FNode(2,FEmpty,FEmpty)) /* We have created several identical object called FEmpty previously We would like to have a single object instead of 4 We can use the "object" keyword. */ FNode(1,FEmpty,FEmpty) == FNode(1,FEmpty,FEmpty) // will return true /* How to we DECOMPOSE or "LOOK INTO" objects? * using pattern matching * */ def isEmpty(t: FTree): Boolean = t match { case FNode(_,_,_) => false case FEmpty => true //case _ => false } def size(t: FTree): Int = t match{ case FEmpty => 0 case FNode(_,left,right) => 1 + size(left) + size(right) } /* ANOTHER implementation of Trees which is structurally equivalent, but the type is differently organised. */ trait OOTree { def isEmpty: Boolean def size: Int } case object OOEmpty extends OOTree { override def isEmpty: Boolean = true override def size: Int = 0 } case class OONode (key: Int, left: OOTree, right: OOTree) extends OOTree { override def isEmpty: Boolean = false override def size: Int = 1 + left.size + right.size } val t2 = OONode(7, OONode(1,OOEmpty,OOEmpty), OONode(2,OOEmpty,OOEmpty)) /* * What is the difference between: FTree and OOTree? * * isEmpty and size are MEMBERS of OOTree while * ----- || ------ are just function of FTree * * THE FIRST IMPLEMEMENTATION (FTree), relies on * pattern-matching, to DECOMPOSE the object * * THE SND IMPL. (OOTree), uses "methods" * */ t2.isEmpty t2.size trait Expr { def eval: Int } case class Val(i: Int) extends Expr{ override def eval:Int = i } case class Add(left: Expr, right: Expr) extends Expr { override def eval: Int = left.eval + right.eval } case class Mult(left: Expr, right: Expr) extends Expr { override def eval: Int = left.eval * right.eval } val e = Add(Val(2),Mult(Val(3),Val(4))) e.eval