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)
}
Related
TL;DR
Given a hierarchy of case classes, a tree of instances can be constructed:
How do I convert that into "something else" via appropriate builders in a type safe (and user friendly) manner (without touching or altering the respective case classes) ?
Update 2021-02-25
I could make it somehow work with
import org.scalajs.dom.console
trait Root
case class Bob(name: String, as: Seq[Root]) extends Root
case class Charles(value: Int, as: Seq[Root]) extends Root
trait Builder[T] {
// can not make T covariant, as this is obj is not in a covariant position
def build(obj: T) : String
}
object Foo {
var r: Map[Root, Builder[Root]] = Map()
def attachBuilder[T <: Root](a: T, builder: Builder[T]) : Unit = {
val e = (a, builder)
r = r + e.asInstanceOf[(Root, Builder[Root])]
}
def b(name : String, as: Root*)(implicit builderB: Builder[Bob]): Bob = {
val b = Bob(name, as)
attachBuilder(b, builderB)
b
}
def c(value: Int, as: Root*)(implicit builderC: Builder[Charles]): Charles = {
val c = Charles(value, as)
attachBuilder(c, builderC)
c
}
def build(obj: Root) : String = {
r(obj).build(obj)
}
}
object UseMe {
implicit val builderB: Builder[Bob] = new Builder[Bob] {
override def build(obj: Bob): String = {
obj.name.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
}
}
implicit val builderC: Builder[Charles] = new Builder[Charles] {
override def build(obj: Charles): String = {
obj.value.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
}
}
def yahoo() : Unit = {
val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))
console.log("This is x: " + Foo.build(x))
}
}
Still, I am very unsatisfied. Idea, I followed: Have a map that catches the respective builder for Bob or Charles. Still,
Builder[T] can not be made covariant. This prevents Builder[Bob] to be a subtype of Builder[Root]
I do not see the proper type signature for Map, so I had to typecast.
Requirements
Hierarchy of Root, Bob, Alice is extensible (so can not be sealed)
No use of static typing (by means of Shapeless HList or similar) as I simply will not have the full types as I am doing computations to assemble the tree.
Questions
What is a better approach?
Original Post
Prelude
Sigh .... mind-bending waste of hours ....... I seriously need your help!
Scenario
Given an ADT
trait A
case class B(name: String, as: Seq[A]) extends A
case class C(value: Int, as: Seq[A]) extends A
that is expected to be extended (not sealed).
Further, assume a
trait Builder[T] {
def build(obj: T) : String
}
Furthermore, with the code below we have "the creator functions" that expect the appropriate builders to in scope.
object Foo {
def b(name : String, as: A*)(implicit builderB: Builder[B]): B = {
???
// How to link ADT instance B with builder for B in a type-safe manner?
// How to trigger builder for `as`: Seq[A] ?
}
def c(value: Int, as: A*)(implicit builderC: Builder[C]): C = {
???
// How to link ADT instance C with builder for C in a type-safe manner?
}
}
With that I want to be able, after defining appropriate builders as implicit vals for B and C to do
object UseMe {
implicit val builderB: Builder[B] = new Builder[B] {
override def build(obj: B): String = {
obj.toString
// and build the as
}
}
implicit val builderC: Builder[C] = new Builder[C] {
override def build(obj: C): String = {
obj.value.toString
// and also build the as
}
}
val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))
// Questions
// How to create a string representation (that is what the builder is doing) for x
// Something like:
// build(x)
}
By intention, I removed all my misleading tries in code, also not to induce any bias.
Tries
A builder impl that uses dynamic type information (via case b: B => ...) is working, but as I expect the ADT to be extended, this is not an option.
All my tries to model by generic types have failed. (Approaches with HList (Shapeless) might be feasible but are not considered, as I think this can be solved in plain Scala)
Questions
How to define methods in Foo?
How to solve builder pattern / creational pattern best for ADTs?
Looking forward to your answers!
I'm using two Scala libraries that both rely on implicit parameters to supply codecs/marshallers for case classes (the libraries in question are msgpack4s and op-rabbit). A simplified example follows:
sealed abstract trait Event
case class SomeEvent(msg: String) extends Event
case class OtherEvent(code: String) extends Event
// Assume library1 needs Show and library2 needs Printer
trait Show[A] { def show(a: A): String }
trait Printer[A] { def printIt(a: A): Unit }
object ShowInstances {
implicit val showSomeEvent = new Show[SomeEvent] {
override def show(a: SomeEvent) =
s"SomeEvent: ${a.msg}"
}
implicit val showOtherEvent = new Show[OtherEvent] {
override def show(a: OtherEvent) =
s"OtherEvent: ${a.code}"
}
}
The Printer for the one library can be generic provided there's an implicit Show for the other library available:
object PrinterInstances {
implicit def somePrinter[A: Show]: Printer[A] = new Printer[A] {
override def printIt(a: A): Unit =
println(implicitly[Show[A]].show(a))
}
}
I want to provide an API that abstracts over the details of the underlying libraries - callers should only need to pass the case class, internally to the API implementation the relevant implicits should be summoned.
object EventHandler {
private def printEvent[A <: Event](a: A)(implicit printer: Printer[A]): Unit = {
print("Handling event: ")
printer.printIt(a)
}
def handle(a: Event): Unit = {
import ShowInstances._
import PrinterInstances._
// I'd like to do this:
//EventHandler.printEvent(a)
// but I have to do this
a match {
case s: SomeEvent => EventHandler.printEvent(s)
case o: OtherEvent => EventHandler.printEvent(o)
}
}
}
The comments in EventHandler.handle() method indicate my issue - is there a way to have the compiler select the right implicits for me?.
I suspect the answer is no because at compile time the compiler doesn't know which subclass of Event handle() will receive, but I wanted to see if there's another way. In my actual code, I control & can change the PrinterInstances code, but I can't change the signature of the printEvent method (that's provided by one of the libraries)
*EDIT: I think this is the same as Provide implicits for all subtypes of sealed type. The answer there is nearly 2 years old, I'm wondering if it's still the best approach?
You have to do the pattern matching somewhere. Do it in the Show instance:
implicit val showEvent = new Show[Event] {
def show(a: Event) = a match {
case SomeEvent(msg) => s"SomeEvent: $msg"
case OtherEvent(code) => s"OtherEvent: $code"
}
}
If you absolutely need individual instances for SomeEvent and OtherEvent, you can provide them in a different object so they can be imported separately.
If Show is defined to be contravariant (i.e. as trait Show[-A] { ... }, with a minus on the generic type) then everything works out of the box and a Show[Event] is usable as a Show[SomeEvent] (and as a Show[OtherEvent] for that matter).
If Show is unfortunately not written to be contravariant, then we might have to do a little bit more juggling on our end than we'd like. One thing we can do is declare all of our SomeEvent values as simply Events, vis a vis val fooEvent: Event = SomeEvent("foo"). Then fooEvent will be showable.
In a more extreme version of the above trick, we can actually hide our inheritance hierarchy:
sealed trait Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X
}
object Event {
private case class SomeEvent(msg: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withSomeEvent(msg)
}
private case class OtherEvent(code: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withOtherEvent(code)
}
def someEvent(msg: String): Event = SomeEvent(msg)
def otherEvent(code: String): Event = OtherEvent(code)
}
Event.someEvent and Event.otherEvent allow us to construct values, and fold allows us to pattern match.
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)
{
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.
I'm looking for a way to have classes that behave just like case classes, but that are automatically hash consed.
One way to achieve this for integer lists would be:
import scala.collection.mutable.{Map=>MutableMap}
sealed abstract class List
class Cons(val head: Int, val tail: List) extends List
case object Nil extends List
object Cons {
val cache : MutableMap[(Int,List),Cons] = MutableMap.empty
def apply(head : Int, tail : List) = cache.getOrElse((head,tail), {
val newCons = new Cons(head, tail)
cache((head,tail)) = newCons
newCons
})
def unapply(lst : List) : Option[(Int,List)] = {
if (lst != null && lst.isInstanceOf[Cons]) {
val asCons = lst.asInstanceOf[Cons]
Some((asCons.head, asCons.tail))
} else None
}
}
And, for instance, while
scala> (5 :: 4 :: scala.Nil) eq (5 :: 4 :: scala.Nil)
resN: Boolean = false
we get
scala> Cons(5, Cons(4, Nil)) eq Cons(5, Cons(4, Nil))
resN: Boolean = true
Now what I'm looking for is a generic way to achieve this (or something very similar). Ideally, I don't want to have to type much more than:
class Cons(val head : Int, val tail : List) extends List with HashConsed2[Int,List]
(or similar). Can someone come up with some type system voodoo to help me, or will I have to wait for the macro language to be available?
You can define a few InternableN[Arg1, Arg2, ..., ResultType] traits for N being the number of arguments to apply(): Internable1[A,Z], Internable2[A,B,Z], etc. These traits define the cache itself, the intern() method and the apply method we want to hijack.
We'll have to define a trait (or an abstract class) to assure your InternableN traits that there is indeed an apply method to be overriden, let's call it Applyable.
trait Applyable1[A, Z] {
def apply(a: A): Z
}
trait Internable1[A, Z] extends Applyable1[A, Z] {
private[this] val cache = WeakHashMap[(A), Z]()
private[this] def intern(args: (A))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(arg: A) = {
println("Internable1: hijacking apply")
intern(arg) { super.apply(arg) }
}
}
The companion object of your class will have to be a mixin of a concrete class implementing ApplyableN with InternableN. It would not work to have apply directly defined in your companion object.
// class with one apply arg
abstract class SomeClassCompanion extends Applyable1[Int, SomeClass] {
def apply(value: Int): SomeClass = {
println("original apply")
new SomeClass(value)
}
}
class SomeClass(val value: Int)
object SomeClass extends SomeClassCompanion with Internable1[Int, SomeClass]
One good thing about this is that the original apply need not be modified to cater for interning. It only creates instances and is only called when they need to be created.
The whole thing can (and should) also be defined for classes with more than one argument. For the two-argument case:
trait Applyable2[A, B, Z] {
def apply(a: A, b: B): Z
}
trait Internable2[A, B, Z] extends Applyable2[A, B, Z] {
private[this] val cache = WeakHashMap[(A, B), Z]()
private[this] def intern(args: (A, B))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(a: A, b: B) = {
println("Internable2: hijacking apply")
intern((a, b)) { super.apply(a, b) }
}
}
// class with two apply arg
abstract class AnotherClassCompanion extends Applyable2[String, String, AnotherClass] {
def apply(one: String, two: String): AnotherClass = {
println("original apply")
new AnotherClass(one, two)
}
}
class AnotherClass(val one: String, val two: String)
object AnotherClass extends AnotherClassCompanion with Internable2[String, String, AnotherClass]
The interaction shows that the Internables' apply method executes prior to the original apply() which gets executed only if needed.
scala> import SomeClass._
import SomeClass._
scala> SomeClass(1)
Internable1: hijacking apply
original apply
res0: SomeClass = SomeClass#2e239525
scala> import AnotherClass._
import AnotherClass._
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
original apply
res1: AnotherClass = AnotherClass#329b5c95
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
res2: AnotherClass = AnotherClass#329b5c95
I chose to use a WeakHashMap so that the interning cache does not prevent garbage collection of interned instances once they're no longer referenced elsewhere.
Code neatly available as a Github gist.
Maybe a little hacky, but you could try defining your own intern() method, like Java's String has:
import scala.collection.mutable.{Map=>MutableMap}
object HashConsed {
val cache: MutableMap[(Class[_],Int), HashConsed] = MutableMap.empty
}
trait HashConsed {
def intern(): HashConsed =
HashConsed.cache.getOrElse((getClass, hashCode), {
HashConsed.cache((getClass, hashCode)) = this
this
})
}
case class Foo(bar: Int, baz: String) extends HashConsed
val foo1 = Foo(1, "one").intern()
val foo2 = Foo(1, "one").intern()
println(foo1 == foo2) // true
println(foo1 eq foo2) // true