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)
Related
I'm trying to generalize some sort of isIntanceOf based on a sealed hierarchy, but haven't been successful. The example below demonstrates what I want to achieve:
sealed abstract class Context
object Context {
case object Context1 extends Context
case class Context2(someInfo: String) extends Context
case object Context3 extends Context
}
case class ContextHolder(id: String, contexts: Set[Context])
import Context._
val holder = ContextHolder("1", Set(Context1, Context2("Other info")))
val contains1Or2 = holder.contexts.contains(Context1) || holder.contexts.exists(_.isInstanceOf[Context2])
val contains3 = holder.contexts.contains(Context3)
println(s"contains1Or2: $contains1Or2")
println(s"contains3: $contains3")
Basically I want to generalize the code of contains1Or2 and contains3 in some sort of:
def containsAnyOf[T <: Context: ClassTag](holder: ContextHolder, contexts: T*): Boolean
And then be able to use it like:
val contains1Or2 = containsAnyOf(holder, Context1, Context2)
val contains3 = containsAnyOf(holder, Context3)
I've already tried a few different approaches, but couldn't get it to work so far. Any ideas? Thanks.
The best I could come up was this:
def containsAnyOf(holder: ContextHolder)(contexts: PartialFunction[Context, Unit]): Boolean = {
val p = contexts.lift.andThen(_.isDefined)
holder.contexts.exists(p)
}
Which you can use like this:
val contains1Or2 = containsAnyOf(holder) {
case Context1 =>
case Context2(_) => // or case _: Contaxt2 =>
}
val contains3 = containsAnyOf(holder) {
case Context3 =>
}
Code running here.
Shapeless's LiftAll type class is very handy here.
import shapeless.ops.hlist.{LiftAll, ToTraversable}
import shapeless.{Generic, HList}
final class ContainsMulti[T <: Product](private val dummy: Boolean = true) extends AnyVal {
def apply[H <: HList, O <: HList](holder: ContextHolder)(implicit
toHList: Generic.Aux[T, H],
classTags: LiftAll.Aux[ClassTag, H, O],
allCtxts: LiftAll[({type E[T] = T <:< Context})#E, H],
toList: ToTraversable.Aux[O, List, ClassTag[_]]
) = classTags.instances.toList
.map(_.runtimeClass)
.forall(klazz => holder.contexts.exists(klazz.isInstance))
}
def containsMulti[T <: Product] = new ContainsMulti[T]
Usage:
val contains1Or2 = containsMulti[(Context1.type, Context2)](holder)
val contains3 = containsMulti[Tuple1[Context3.type]](holder)
val contains1and3 = containsMulti[(Context1.type, Context3.type)](holder)
val check = containsMulti[(Int, String)](holder) //doesn't compile
println(s"contains1Or2: $contains1Or2") //true
println(s"contains3: $contains3") //false
println(s"contains1and3: $contains1and3")//false
See it run.
All the implicits may seem daunting, but it's actually very simple. The extra class is so we can take multiple type parameter lists, where the first is explicitly given, and the second is inferred. Generic turns the inputted tuple into an HList, LiftAll finds the ClassTag instances for each of the types in the tuple, and ToTraversable turns the HList containing those class tags back into a List.
As Luis Miguel Mejía Suárez suggested, I have made ContainsMulti a value class, using the partially applied type trick to avoid object creation. They also pointed out that this approach initially allowed (Int, String) as input, so now allCtxts checks that all the types in the HList extend Context.
I have a type hierarchy and want to ask a lookup method for an implementation. I am having trouble doing this without resorting to an asInstanceOf call.
So giving a simple type hierarchy like so
trait Vehicle
trait Flying extends Vehicle
class Plane extends Flying
trait Driving extends Vehicle
class Car extends Driving
trait Swimming extends Vehicle
class Boat extends Swimming
my lookup method is like this
def findVehicle[V <: Vehicle](implicit tag: TypeTag[V]): Option[V] = {
val v = tag.tpe match {
case t if t =:= typeOf[Flying] => Some(new Plane)
case t if t =:= typeOf[Driving] => Some(new Car)
case t if t =:= typeOf[Swimming] => Some(new Boat)
case _ => None
}
v.map(_.asInstanceOf[V])
}
with a lookup like so
println(findVehicle[Flying]) // Some(Plane#5b7fd935)
Is it possible to achieve a lookup like this without the asInstanceOf at the end?
You can avoid using TypeTag and use a type class instead.
trait Builder[+T] {
def build: Option[T]
}
implicit val flyingBuilder = new Builder[Flying] {
def build = Some(new Plane)
}
implicit val drivingBuilder = new Builder[Driving] {
def build = Some(new Car)
}
implicit val swimmingBuilder = new Builder[Swimming] {
def build = Some(new Boat)
}
implicit val anyBuilder = new Builder[Nothing] {
def build = None
}
def findVehicle[V <: Vehicle](implicit b: Builder[V]): Option[V] = b.build
No reflection involved and it's definitely more idiomatic.
Note how defining a Builder[Nothing] reproduces the same behavior you achieved by returning a None. This is not necessarily a good idea, as you're now forced to check whether the method was able to produce a value or not.
I would rather prefer a compile-time error if it's impossible to build the instance of the desired type, and you achieve it by directly returning T as opposed to Option[T] from build (and of course getting rid of the Nothing case).
Example code:
trait A
case class B() extends A
case class C() extends A
trait D[T]
implicit object DB extends D[B]
implicit object DC extends D[C]
def getImplicit[T: D](arg: T) = implicitly[D[T]]
val list = Seq(B(), C())
list map getImplicit
how can i get implicits without explicitly casting objects in list? maybe i can do it with HList? or perhaps macros can help me?
i tried:
case class Wrap[T](v: T)
object getImplicit extends (Wrap ~> D) {
def apply[T](arg: Wrap[T]) = implicitly[D[T]]
}
val list = Wrap(B()) :: Wrap(C()) :: HNil
list map getImplicit
and i get compilation error:
could not find implicit value for parameter e: D[T]
def apply[T](arg: Wrap[T]) = implicitly[D[T]]
You will have to supply the type class to the apply method of getImplicit. Unfortunately that means you'll have to use the long form of Poly1:
object getImplicit extends Poly1 {
implicit def default[T: D] = at[Wrap[T]](_ => implicitly[D[T]])
}
After this change, your code will compile.
What I try to do is to come up with a case class which I can use in pattern matching which has exactly one field, e.g. an immutable set. Furthermore, I would like to make use of functions like map, foldLeft and so on which should be passed down to the set. I tried it as in the following:
case class foo(s:Set[String]) extends Iterable[String] {
override def iterator = s.iterator
}
Now if I try to make use of e.g. the map function, I get an type error:
var bar = foo(Set() + "test1" + "test2")
bar = bar.map(x => x)
found : Iterable[String]
required: foo
bar = bar.map(x => x)
^
The type error is perfectly fine (in my understanding). However, I wonder how one would implement a wrapper case class for a collection such that one can call map, foldLeft and so on and still receive an object of the case class. Would one need to override all these functions or is there some other way around?
Edit
I'm inclined to accept the solution of Régis Jean-Gilles which works for me. However, after Googling for hours I found another interesting Scala trait named SetProxy. I couldn't find any trivial examples so I'm not sure if this trait does what I want:
come up with a custom type, i.e. a different type than Set
the type must be a case class (we want to do pattern matching)
we need "delegate" methods map, foldLeft and so on which should pass the call to our actual set and return the resulting set wrapped arround in our new type
My first idea was to extend Set but my custom type Foo already extends another class. Therefore, the second idea was to mixin the trait Iterable and IterableLike. Now I red about the trait SetProxy which made me think about which is "the best" way to go. What are your thoughts and experiences?
Since I started learning Scala three days ago, any pointers are highly appreciated!
Hmm this sounds promissing to me but Scala says that variable b is of type Iterable[String] and not of type Foo, i.e. I do not see how IterableLike helps in this situation
You are right. Merely inheriting from IterableLike as shown by mpartel will make the return type of some methods more precise (such as filter, which will return Foo), but for others such as map of flatMap you will need to provide an appopriate CanBuildFrom implicit.
Here is a code snippet that does just that:
import collection.IterableLike
import collection.generic.CanBuildFrom
import collection.mutable.Builder
case class Foo( s:Set[String] ) extends Iterable[String] with IterableLike[String, Foo] {
override def iterator = s.iterator
override protected[this] def newBuilder: scala.collection.mutable.Builder[String, Foo] = new Foo.FooBuilder
def +(elem: String ): Foo = new Foo( s + elem )
}
object Foo {
val empty: Foo = Foo( Set.empty[String] )
def apply( elems: String* ) = new Foo( elems.toSet )
class FooBuilder extends Builder[String, Foo] {
protected var elems: Foo = empty
def +=(x: String): this.type = { elems = elems + x; this }
def clear() { elems = empty }
def result: Foo = elems
}
implicit def canBuildFrom[T]: CanBuildFrom[Foo, String, Foo] = new CanBuildFrom[Foo, String, Foo] {
def apply(from: Foo) = apply()
def apply() = new FooBuilder
}
}
And some test in the repl:
scala> var bar = Foo(Set() + "test1" + "test2")
bar: Foo = (test1, test2)
scala> bar = bar.map(x => x) // compiles just fine because map now returns Foo
bar: Foo = (test1, test2)
Inheriting IterableLike[String, Foo] gives you all those methods such that they return Foo. IterableLike requires you to implement newBuilder in addition to iterator.
import scala.collection.IterableLike
import scala.collection.mutable.{Builder, SetBuilder}
case class Foo(stuff: Set[String]) extends Iterable[String] with IterableLike[String, Foo] {
def iterator: Iterator[String] = stuff.iterator
protected[this] override def newBuilder: Builder[String, Foo] = {
new SetBuilder[String, Set[String]](Set.empty).mapResult(Foo(_))
}
}
// Test:
val a = Foo(Set("a", "b", "c"))
val b = a.map(_.toUpperCase)
println(b.toList.sorted.mkString(", ")) // Prints A, B, C
Having defined a class A which extends Ordering[A], and a subclass B of A, how do I automatically sort an Array of Bs? The Scala compiler complains that it "could not find implicit value for parameter ord: Ordering[B]". Here's a concrete REPL example (Scala 2.8), with A = Score and B = CommentedScore:
class Score(val value: Double) extends Ordered[Score] {
def compare(that: Score) = value.compare(that.value)
}
defined class Score
trait Comment { def comment: String }
defined trait Comment
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment
defined class CommentedScore
val s = new CommentedScore(10,"great")
s: CommentedScore = CommentedScore#842f23
val t = new CommentedScore(0,"mediocre")
t: CommentedScore = CommentedScore#dc2bbe
val commentedScores = Array(s,t)
commentedScores: Array[CommentedScore] = Array(CommentedScore#b3f01d, CommentedScore#4f3c89)
util.Sorting.quickSort(commentedScores)
error: could not find implicit value for parameter ord: Ordering[CommentedScore]
util.Sorting.quickSort(commentedScores)
^
How do I fix this (that is, sort an Array[B] = Array[CommentedScore] "for free", given that I know how to sort Array[A] = Array[Score]), in an elegant manner which avoids boilerplate?
Thanks!
Add the required implicit yourself:
implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)
You can put this in a CommentedScore companion object so that there is no boilerplate at use-site.
Edit: if you want the ordering method to be defined only at the top of the inheritance tree, you still have to provide an Ordering for each subclass, but you can define the compare method of the Ordering in terms of the one in the Score object. i.e.
object Score {
implicit val ord: Ordering[Score] = Ordering.by(_.value)
}
object CommentedScore {
implicit val csOrd = new Ordering[CommentedScore] {
def compare(x: CommentedScore, y: CommentedScore) = Score.ord.compare(x, y)
}
}
if you don't want to re-define this for each sub-class, you can use a generic method to produce the Ordering:
object Score {
implicit def ord[T <: Score]: Ordering[T] = Ordering.by(_.value)
}
This is a bit less efficient since being a def rather than a val, it creates a new Ordering each time one is required. However the overhead is probably tiny. Also note, the Ordered trait and compare method is not necessary now we have Orderings.
You might use Order from scalaz, which is contravariant, so you need not to define it for every subclass. Here is an example:
import scalaz._
import Scalaz._
class Score(val value: Double)
object Score {
implicit val scoreOrd: Order[Score] = orderBy(_.value)
}
trait Comment { def comment: String }
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment {
override def toString = s"cs($value, $comment)"
}
def quickSort[E: Order](list: List[E]): List[E] = list match {
case Nil => Nil
case head :: tail =>
val (less, more) = tail partition { e => implicitly[Order[E]].order(e, head) == LT }
quickSort(less) ::: head :: quickSort(more)
}
println(quickSort(List(
new CommentedScore(10,"great"),
new CommentedScore(5,"ok"),
new CommentedScore(8,"nice"),
new CommentedScore(0,"mediocre")
))) // List(cs(0.0, mediocre), cs(5.0, ok), cs(8.0, nice), cs(10.0, great))
This works:
val scoreArray: Array[Score] = Array(s, t)
util.Sorting.quickSort(scoreArray)
Or if you are starting from the Array[CommentedScore]:
val scoreArray: Array[Score] = commentedScores.map(identity)
util.Sorting.quickSort(scoreArray)
Note you can sort more simply with:
scoreArray.sorted