I was thinking about something, I wrote this trait with two classes extending it and another class that may contain them:
sealed trait MainObj
case object subObj1 extends mainObj
case Object subObj2 extends mainObj
case class AnotherClass(val mo: Option[MainObj], val amount: Int)
Now let's say I wanted to write a function that added the amounts in twoAnotherClass objects but only if the optional MainObj inside each of them were the same type. Like only add if both are subObj1.
So I could do something like this:
def add(one: AnotherClass, two: AnotherClass): AnotherClass = one. mo, two.mo match {
case (Some(x), Some(y)) if i and x are the same class => return a `AnotherClass` with the two integers added from `one` and `two`
etc..
I wondered whether there was another way of doing this? I don't know whether this is a "functional" way of doing it or whether there is a less verbose way?
I ask because essentially I could write some more methods like subtract, multiply, etc ... and I have some very common code.
I could extract that common code and write a function that simply takes two of the subObjs and an operation and then apply that operation on the two objects, but that only abstracts out the common operation, could the main pattern matching part be written differently that may be considered more concise(for lack of a better word)?
Just add the 'add' method to the case class :
sealed trait MainObj
case object SubObj1 extends MainObj
case object SubObj2 extends MainObj
case class AnotherClass(val mo: Option[MainObj], val amount: Int){
def add(that:AnotherClass):AnotherClass = {
if (that.mo == this.mo)
this.copy(amount = this.amount + 1)
else
this
}
}
val x = AnotherClass(Some(SubObj1), 1)
val y = AnotherClass(Some(SubObj1), 1)
val z = AnotherClass(Some(SubObj2), 1)
scala> x add y
res5: AnotherClass = AnotherClass(Some(SubObj1),2)
scala> x add z
res6: AnotherClass = AnotherClass(Some(SubObj1),1)
scala> val l = List(x,y,z)
l.reduce ( _ add _)
res7: AnotherClass = AnotherClass(Some(SubObj1),2)
val mo = two.mo
one match {
case AnoterClass(`mo`, am) =>
one.copy(amount = am + two.amount)
case _ => ???
}
Related
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
}
Trait GenericLinkedList , case class Cons and case object Nil were created like below.
The question is I want to use this genericLinkedList however as you know when we write this code var list = new GenericLinkedList , it will not cause Traits cannot create any object , Right? I want to create a class which extends GenericLinkedList but I cannot. How can I fix it ?
trait GenericLinkedList [+T] {
def prepend[TT >: T](x: TT): GenericLinkedList[TT] = this match {
case _ => Cons(x,this)
}
}
case class Cons[+T](head: T,tail: GenericLinkedList[T]) extends GenericLinkedList[T]
case object Nil extends GenericLinkedList[Nothing]
Your issue seems to be unable of doing
val list = new GenericLinkedList
Is your goal creating an empty list?
You can do
val list = new GenericLinkedList[Int] { }
since the trait is not abstract, but it's not pretty. You can alternatively define a companion object for your trait
object GenericLinkedList {
def apply[T](): GenericLinkedList[T] = Nil
}
and use it to initialize an empty list this way
scala> val x = GenericLinkedList[Int]()
// x: GenericLinkedList[Int] = Nil
scala> x.prepend(42)
// res0: GenericLinkedList[Int] = Cons(42,Nil)
By the way, the universal match in the prepend implementation is useless. You can just do
def prepend[TT >: T](x: TT): GenericLinkedList[TT] = Cons(x, this)
The ast is written using case classes and its heavily nested. After parsing ,I would like to have a deep copy of it, and manipulate the copies independently.
Like #AlexeyRomanov said, you can write a recursive copy function yourself.
A small example:
trait A
case class B(a0: A, a1: A) extends A
case class C(value: Int) extends A
def copy(a: A): A = a match {
case B(a0, a1) => B(copy(a0), copy(a1))
case C(value) => C(value)
}
val a = B(C(0), B(C(1), C(2)))
val aCopy = copy(a)
a == aCopy //true
a eq aCopy //false
{
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.
Im trying to create a parser for a small language with commands including labels and goto:
...
lazy val cmds = opt("{")~>rep(cmd<~opt(";"))<~opt("}") ^^ {...}
lazy val cmd = ("if"~boolexpr~"then"~cmds~"else"~cmds
^^ { case _~b~_~c1~_~c2 => IFCMD(boolexpr,c1
| ident ~":="~numericLit ^^ {case i1~_~v => ASSIGN(i1,v) }
| "goto" ~>ident ^^ { case l => GOTO(l) }
| ident~":"~cmd ^^ { case l~_~c => <APPENDLABELTO_CORE>
...
the GOTO, IFCMD etc are case classes extending abstract class Core
In keeping with the functional/scala-like/immutable-objecty -way I'm thinking that defining Core like this is wrong:
abstract class Core(var label:Option[String] = None )
but would allow me to replace the part with <APPENDLABELTO_CORE> with:
| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c }
Can anyone point out the "scalaish" way to do this?
( I've tried c copy (label=Some(l)) but the abstract base class hasn't got the automatic copy constructor magic )
It is entirely possible to create your own copy-like method:
abstract class Core(val label: Option[String]) {
def set(label: Option[String]): Core
}
class Impl(label: Option[String] = None) extends Core(label) {
def set(label: Option[String] = this.label) = new Impl(label)
}
used thusly:
scala> val i = new Impl
i: Impl = Impl#1930ebb
scala> i.label
res0: Option[String] = None
scala> i.set(label = Some("thing"))
res1: Impl = Impl#b28f30
scala> res1.label
res2: Option[String] = Some(thing)
But, pragmatically, I wouldn't be too quick to dismiss the use of vars here. It is easier to reason about immutable values, but the ones you get are pretty well isolated within the parser, as far as I can tell. An alternative idea would be to create a method that converts everything to an immutable version at the end, or if the parser code ends up storing all the data elsewhere anyway, just leaving it mutable.
Another way to go is to make the abstract class not abstract, but to actually make it a case class. You can derive classes from a case class (deriving case classes from case classes is a no-no, however). The trick then would be to make your variable data that you may need to preserve live in a field:
abstract class SpecializedStuff { }
case class ParticularStuff(val i: Int) extends SpecializedStuff
case class Core(details: SpecializedStuff, label: Option[String] = None)
class Impl(p: ParticularStuff) extends Core(p)
scala> val i = new Impl( ParticularStuff(5) )
i: Impl = Core(ParticularStuff(5),None)
scala> i.copy(label = Some("thing"))
res0: Core = Core(ParticularStuff(5),Some(thing))