How to get numbers from two objects and add them in Scala - scala

I'm trying to make an add function but it's too hard.
I get 2 numbers from an object and add them, how do I do that?
My code:
def add(a: Object, b: Object): Object = ???
sealed abstract class Object
case class Number(num: Int) extends Object

Use pattern matching to 1) insure that both args are type Number (not some other sub-type of Object), and 2) extract the Int from each Number so that they can be combined in the result Number.
def add(a: Object, b: Object): Object = (a,b) match {
case (Number(x), Number(y)) => Number(x+y)
case _ => throw new Error("not implemented yet")
}

Related

Scala: Printing a Binary Tree That's a Class

Hello I am new to Scala and I'm having a hard time getting my class to print some values out.
class TreeDemo[T](implicit o : T => Ordered[T]) {
sealed trait BinaryTree
case object Empty extends BinaryTree
case class Node(left:BinaryTree, d:T, right:BinaryTree) extends BinaryTree
// construct a "leaf" node
def Leaf(d : T) : BinaryTree = Node(Empty,d,Empty)
// remove all nodes equal to x from tree t
def remove(t : BinaryTree, x : T) : BinaryTree = {
replace(t, x, Empty)
}
val myTree = Node(Node(Leaf(1),2,Leaf(3)),4,Leaf(5))
val x = remove(myTree, 2)
def main (args: Array[String]) {
println(x)
}
}
From the code above I am trying to print the remove def but I am getting errors.
If you want remove to remove nodes in place from the tree, then you will want var values. I was not sure because replace is missing from your snippet
As comments point out, Node can only take T until you instantiate an actual TreeDemo, so at the time of definition of the class, you cannot create Nodes of specific types, such as Leaf(1) etc. because it would be a type mismatch.
It seems the type variable should be on BinaryTree itself, since you want your demo to try out specific trees, and it can be covariant (+T) to allow for Empty to be any other valid BinaryTree.
Left and right trees of a node should have the same types as the node.
You can override toString to allow for more informative printing
A method called main inside of a class doesn't serve as an entry-point. In Java, only a static void main will serve as an application entry-point. In Scala, main should also be in static (in an object instead of a class) in order to run.
sealed trait BinaryTree[+T]
case object Empty extends BinaryTree[Nothing]
class Node[T](var left:BinaryTree[T], var d:T, var right:BinaryTree[T])(implicit val ordering: Ordering[T]) extends BinaryTree[T] {
override def toString: String = (left, right) match {
case (Empty, Empty) => s"(${d})"
case (Empty, right) => s"(${left},${d})"
case (left, Empty) => s"(${d}, ${right})"
case _ => s"(${left}, ${d}, ${right})"
}
}
object Node{
// define remove here (if static) or in the class
def apply[T:Ordering](t: T) = new Node[T](Empty, t, Empty)
def apply[T:Ordering](left:BinaryTree[T], t: T) = new Node[T](left, t, Empty)
def apply[T:Ordering](left:BinaryTree[T], t: T, right:BinaryTree[T]) = new Node[T](left, t, right)
def apply[T:Ordering](t: T, right:BinaryTree[T]) = new Node[T](Empty, t, right)
}
// either extend App, or have a main method, but use an object
object TreeApp extends App {
val myTree = Node(Node(Node(1),2,Node(3)),4,Node(5))
println(myTree)
}

Scala generics: How to declare that a type must be a case class?

I have several case classes with a count field. It's 1 by default, and I have a reduce in my code that groups duplicates and sums that value to find the number of each object. E.g.:
case class Person(name: String, count = 1)
personList.groupBy(_.name).reduce((x,y) => x.copy(count = x.count + 1))
I have this logic in several case classes, and since my logic is a bit more complicated than the example above I want to create a generic merging function.
So I've created a sealed trait with a count field. I've then changed my case classes to extend from this, e.g.:
case class Person(name: String, override val count) extends Countable
So far, so good.
However, I can't work out how to declare my merge function so that it only accepts case classes that extend Countable. Because of that, it can't find the copy method.
Here's what I have:
def merge[T <: Countable](f: T => Seq[String])(ms: Seq[T]): Vector[T] =
ms.groupBy(x => f(x).mkString("_")).mapValues(_.reduce { (x,y) =>
x.copy(count = x.count + 1) // can't find `copy`
}).values.toVector
Is there a typeclass that I can also include that means a type has a copy method (or is a case class) using Scala 2.11.7?
Update:
Countable trait is:
sealed trait Countable {
def timesSeen: Long = 1
}
How did you defined you Countable trait.
Following snippet works fine for me:
trait Countable[Z] {
def count: Int
def copy: Z
}
case class Person(name: String, override val count: Int) extends Countable[Person] {
override def copy: Person = this
}
def merge[T <: Countable[T]](f: T => Seq[String])(ms: Seq[T]): Vector[T] = {
val r = ms.groupBy(x => f(x).mkString("_")).mapValues(_.reduce { (x, y) =>
x.copy
}).values.toVector
r
}

Evaluate String as a generic function or function call in Scala

I want to write a generic function functionChooser which will choose which function to use from a few options, based on a String argument.
This works:
def a (arg: String) = arg + " with a"
def b (arg: String) = arg + " with b"
def c (arg: String) = arg + " with c"
def functionChooser(func: String, additionalArg: String) = {
val f = func match {
case "a" => a _
case "b" => b _
case _ => c _
}
f(additionalArg)
}
scala> functionChooser("a", "foo")
res18: String = foo with a
I'm having trouble in making functionChooser generic, e.g. when functions a, b, and c return different case classes:
case class A(s: String)
case class B(s: String)
case class C(s: String)
def a (arg: String) = A(arg)
def b (arg: String) = B(arg)
def c (arg: String) = C(arg)
//functionChooser def as before
scala> functionChooser("a", "foo")
res19: Product with Serializable = A(foo)
I don't quite understand what I got there, I know I get an error when calling functionChooser("a", "foo").s ("error: value s is not a member of Product with Serializable").
Lastly, what I really want is that the functions would return Lists of these case classes, e.g.:
def a (arg: String) = List(A(arg))
def b (arg: String) = List(B(arg))
def c (arg: String) = List(C(arg))
So functionChooser should be generic to List[T] where T is some class.
The function functionChooser will return the most specific common super type of the case classes A, B and C. Since case classes inherit from Product and Serializable, the common super type is Product with Serializable.
If you want to access the case class field s you either have to cast the result, via pattern matching, or you provide a common base class of all your classes A, B and C which allows you to access the field.
trait Base {
def s: String
}
case class A(s: String) extends Base
case class B(s: String) extends Base
case class C(s: String) extends Base
With this type definition the return type of functionChooser would be Product with Serializable with Base and, thus, the result would allow you to access s.
If your function a, b and c return a List of the respective case class, then the return type of functionChooser would be List[Product with Serializable with Base].
Update
If you cannot change the class hierarchy, then you either have to cast the result or you could extract the necessary information in the functionChooser and wrap it in another type which contains the super set of all data you need. E.g.
def functionChooser(func: String, additionalArg: String): String = {
val f = func match {
case "a" => (a _).s
case "b" => (b _).s
case _ => (c _).s
}
f(additionalArg)
}
Note: Here I only extract the field s which is the super set of all required information.
You should return the upper common type for all three functions. Object (AnyRef) always fit.
def functionChooser(func: String, additionalArg: String) : AnyRef = {
In your case, where all possible returning values are Lists you may use more specific type:
def functionChooser(func: String, additionalArg: String) : List[_] = {
Of course that will eliminate type information. Any method should return the same type, it could not be polymorphic on it. So, you need to use .asInstanceOf[T] case further, to get this information back.
That make sense, because the actual type is unknown during runtime. e.g. the dispatcher string may be entered by user. If it would be known during compile time, then you could just use appropriate method without referring to descriptive string.
If you would like to get some common behaviour for all possible return types, than you should define a common trait for them and place common methods to it.

Scala: Convert nested value classes to Vector

I have some type safe case classes that i want to turn into a vector:
case class Bdrms(underlying: Double) extends AnyVal
object Bdrms {
implicit def toBdrm(x: Double): Bdrms = Bdrms(x)
}
case class Bath(underlying: Double) extends AnyVal
object Bath {
implicit def toBath(x: Double): Bath = Bath(x)
}
// same pattern for many (20-30) other variables. sq ft, price, etc.
// and a parent case class
case class RealEstateDataPoint(bdrm: Bdrm, bath: Bath, sqft: Sqft,//)
one service needs to use these Doubles in the form of a Vector. if value classes were not used, i.e. if we just had
case class RealEstateDatePoint(bdrm: Double, bath: Double...)
then something like the following works to iterate over the fields to create a vector:
def toVector(dataCC: RealEstateDataPoint): Vector[Double] = {
val m = dataCC.productArity
val vector = Vector(m)
for (i<-0 until m) {
vector(i) = dataCC.productElement(i).asInstanceOf[Double]
}
vector
}
But of course, the asInstanceOf type cast wont work with our value classes. Is there an idiomatic/efficient way to make the conversion to a vector?
You can use structural typing:
dataCC.productIterator.map {
case h:{ val underlying: Double } => h.underlying
}.toVector
You might also consider making all the case classes inherit some trait:
trait HasUnderlying { val underlying: Double }
case class Bdrms(val underlying: Double) extends HasUnderlying
And then you can get the desired vector as:
dataCC.productIterator.map {
case h: HasUnderlying => h.underlying
}.toVector

Why are constructor parameters made into members for case classes?

{
class MyClass(name: String) {}
val x = new MyClass("x")
println(x.name) // Error name is not a member of MyClass
}
but
{
abstract class Base
case class MyClass(name: String) extends Base {}
var x = new MyClass("x")
println(x.name) // name is a member of MyClass
}
So, what's the deal with case classes? Why are all of the constructor parameters turned into variables.
name is member in both examples, but private in your first example while public in your second. Case classes make their constructor parameters public val by default.
Pattern matching is the most important but not the only application for case classes. Another important point is that they implement the equals and hashCode methods in terms of the constructor arguments (aka product elements). Therefore, case classes are very useful for defining data structures that serve as elements in sets or keys in maps. That in turn only makes sense if these elements are visible.
Compare:
class Foo(val i: Int)
val set1 = Set(new Foo(33))
set1.contains(new Foo(33)) // false!!
And:
case class Bar(val i: Int)
val set2 = Set(Bar(33)
set2.contains(Bar(33)) // true!
Two case class instances with equal parameters are equal themselves. You can imagine them representing some "constants". This implies that you should not have mutable state in them.
You can, however, use a second parameter list to exclude arguments from the equality:
case class Baz(i: Int)(val n: Long)
Baz(33)(5L) == Baz(33)(6L) // true!
Another useful feature which implies that the constructor arguments become values, is making copies. This is the way immutable data is changes—you create a new instance with a particular value changed, leaving the original value in place.
case class Person(name: String, age: Int)
val p1 = Person("Fuzzi", 33)
val p2 = p1.copy(age = 34)
The copy method uses default values for all unspecified argument, taking those values from the constructor args.
Just to be clear, the constructor arguments aren't used to create variables, they're used to create values.
If you specify val in your first example, the non-case class:
class MyClass(val name: String) {}
then you also get the argument translated into a public value, the same as is done for the case class.
In the example on the Scala-Lang site it says:
It makes only sense to define case classes if pattern matching is used
to decompose data structures. The following object defines a pretty
printer function for our lambda calculus representation:
followed by the example code:
object TermTest extends Application { def printTerm(term: Term) {
term match {
case Var(n) =>
print(n)
case Fun(x, b) =>
print("^" + x + ".")
printTerm(b)
case App(f, v) =>
Console.print("(")
printTerm(f)
print(" ")
printTerm(v)
print(")")
} } def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false } val id = Fun("x", Var("x")) val t = Fun("x", Fun("y", App(Var("x"), Var("y")))) printTerm(t) println println(isIdentityFun(id)) println(isIdentityFun(t)) }
To add something to my comment due to lack of available space: consider the following example case class:
case class My(x: Int)
If you save it to file and pass it to scalac -print, you get following expanded code (I removed unimportant stuff):
case class My extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def x(): Int = My.this.x;
Notice <caseaccessor>s here.
And then companion object:
<synthetic> object My extends runtime.AbstractFunction1 with Serializable {
case <synthetic> def apply(x: Int): My = new My(x);
case <synthetic> def unapply(x$0: My): Option = if (x$0.==(null))
scala.this.None
else
new Some(scala.Int.box(x$0.x()));
case <synthetic> <bridge> def apply(v1: Object): Object = My.this.apply(scala.Int.unbox(v1));
//...
Notice apply and unapply here. If you look at complete output yourself, you'll learn more about how scala generates your code.