My problem is that i want to mix in traits to some existing object instance
instead of doing
sealed trait Type
trait A extends Type
trait B extends Type
case class Basic(int, bool)
val someInt = 2
val someBool = False
val someType = "a"
someType match {
case "a" => new Basic(someInt, someBool) with A
case "b" => new Basic(someInt, someBool) with B
}
i would like to do new Basic() only once
and then add somehow A and B
Is it possible to do it somehow with Shapeless ?
I was hoping to be able to use Generic to get a HList, add the marker trait info in it, and convert it back to what would be a Basic with the trait attached. But I don't actually see how that would be possible with HList.
For example you can define a Poly.
import shapeless.Poly1
object myPoly extends Poly1 {
implicit val aCase: Case.Aux[A, Basic with A] = at(_ => new Basic() with A)
implicit val bCase: Case.Aux[B, Basic with B] = at(_ => new Basic() with B)
}
myPoly(new A {})
myPoly(new B {})
I guess HList is irrelevant here since Generic transforms Type into a coproduct rather than HList.
import shapeless.{:+:, CNil, Generic}
sealed trait Type
case class A() extends Type
case class B() extends Type
implicitly[Generic.Aux[Type, A :+: B :+: CNil]]
You can use Poly and singleton types:
import shapeless.{Poly1, Witness}
import shapeless.syntax.singleton._
sealed trait Type
trait A extends Type
trait B extends Type
case class Basic(int: Int, bool: Boolean)
val someInt: Int = 2
val someBool: Boolean = false
val someType: String = "a"
object myPoly extends Poly1 {
implicit val aCase: Case.Aux[Witness.`"a"`.T, Basic with A] = at(_ => new Basic(someInt, someBool) with A)
implicit val bCase: Case.Aux[Witness.`"b"`.T, Basic with B] = at(_ => new Basic(someInt, someBool) with B)
}
myPoly("a".narrow)
myPoly("b".narrow)
// myPoly("c".narrow) // doesn't compile
Related
I have the following code:
sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
trait Show[A] {
def show(a: A): String
}
class Processor[A](a: A) {
def print(implicit S: Show[A]): Unit = println(S.show(a))
}
implicit val showCat: Show[Cat] = c => s"Cat=${c.name}"
implicit val showDog: Show[Dog] = d => s"Dog=${d.name}"
val garfield = Cat("Garfield")
val odie = Dog("Odie")
val myPets = List(garfield, odie)
for (p <- myPets) {
val processor = new Processor(p)
processor.print // THIS FAILS AT THE MOMENT
}
Does anyone know of a nice way to get that line processor.print working?
I can think of 2 solutions:
pattern match the p in the for loop.
create an instance of Show[Animal] and pattern match it against all its subtypes.
But I'm wondering if there's a better way of doing this.
Thanks in advance!
Compile error is
could not find implicit value for parameter S: Show[Product with Animal with java.io.Serializable]
You can make Animal extend Product and Serializable
sealed trait Animal extends Product with Serializable
https://typelevel.org/blog/2018/05/09/product-with-serializable.html
Also instead of defining implicit Show[Animal] manually
implicit val showAnimal: Show[Animal] = {
case x: Cat => implicitly[Show[Cat]].show(x)
case x: Dog => implicitly[Show[Dog]].show(x)
// ...
}
you can derive Show for sealed traits (having instances for descendants) with macros
def derive[A]: Show[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
val cases = subclasses.map{ subclass =>
cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
}
q"""
new Show[$typA] {
def show(a: $typA): _root_.java.lang.String = a match {
case ..$cases
}
}"""
}
implicit val showAnimal: Show[Animal] = derive[Animal]
or Shapeless
implicit val showCnil: Show[CNil] = _.impossible
implicit def showCcons[H, T <: Coproduct](implicit
hShow: Show[H],
tShow: Show[T]
): Show[H :+: T] = _.eliminate(hShow.show, tShow.show)
implicit def showGen[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
show: Show[C]
): Show[A] = a => show.show(gen.to(a))
or Magnolia
object ShowDerivation {
type Typeclass[T] = Show[T]
def combine[T](ctx: CaseClass[Show, T]): Show[T] = null
def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
value => ctx.dispatch(value) { sub =>
sub.typeclass.show(sub.cast(value))
}
implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
}
import ShowDerivation.gen
or Scalaz-deriving
#scalaz.annotation.deriving(Show)
sealed trait Animal extends Product with Serializable
object Show {
implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Prod[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = null
override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Cop[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = z => {
val x = g(z).zip(tcs)
x.b.value.show(x.a)
}
}
}
For cats.Show with Kittens you can write just
implicit val showAnimal: Show[Animal] = cats.derived.semi.show
The thing is that garfield and odie in List(garfield, odie) have the same type and it's Animal instead of Cat and Dog. If you don't want to define instance of type class for parent type you can use list-like structure preserving types of individual elements, HList garfield :: odie :: HNil.
For comparison deriving type classes in Scala 3
How to access parameter list of case class in a dotty macro
The most general solution is to just pack the typeclass instances in at the creation of myPets, existentially
final case class Packaged[+T, +P](wit: T, prf: P)
type WithInstance[T, +P[_ <: T]] = Packaged[U, P[U]] forSome { type U <: T }
implicit def packageInstance[T, U <: T, P[_ <: T]]
(wit: U)(implicit prf: P[U])
: T WithInstance P
= Packaged(wit, prf)
val myPets = List[Animal WithInstance Show](garfield, odie)
for(Packaged(p, showP) <- myPets) {
implicit val showP1 = showP
new Processor(p).print // note: should be def print()(implicit S: Show[A]), so that this can be .print()
}
I am playing with scala and I was trying to create a method that would return a list of instances filtered by a given type (passed through parameters of the function):
I tried the following, but it is not even compiling:
trait A
trait B extends A
trait C extends A
case class B1() extends B {}
case class B2() extends B {}
case class C1() extends C {}
case class C2() extends C {}
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
case f: F => Some(f)
case _ => None
}
val list: List[A] = List(B1(), B2(), C1(), C2()) // type of A
val filteredList: List[B] = filterByType(list, Class[B]) // This should return a sublist like List(B1(), B2()) and be type of B
println(filteredList)
Is there a way to do something like this in scala? What would be the correct way of doing this?
Thanks!
EDIT:
I have also tried passing classOf[B] with no luck either.
You can do something like this:
(using ClassTag)
trait A
trait B extends A
final case class B1() extends B
final case class B2() extends B
trait C extends A
final case class C1() extends C
final case class C2() extends C
import scala.reflect.ClassTag
def filterByType[F <: A : ClassTag](list: List[A]): List[F] =
list.collect {
case f: F => f
}
Which you can use like this:
val list: List[A] = List(B1(), B2(), C1(), C2())
val filteredList: List[B] = filterByType[B](list)
// filteredList: List[B] = List(B1(), B2())
Note: Due type erasure this has some limitations, but it seems it will work for your use case.
For a more general approach I would create my own typeclass.
With only Class[F] you can do
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
case f if t.isInstance(f) => Some(t.cast(f))
case _ => None
}
or shorter but less efficient
def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
x => Try { t.cast(x) }.toOption
}
As Luis Miguel Mejía Suárez's answer shows, pattern matching has special support for : F is a ClassTag[F] is available, but it doesn't extend to anything else.
I'm trying to convert a case class into another via conversion to HList.
case class Source(p1:S1, p2:S2) -> HList[S1:+:S2] -> HList[D1:+:D2] ->case class Destination(p1:D1,p2:D2)
I can convert from Source to HList via gem.to and from HList to Destination via gen.from.
I wrote a Converter for each type of parameter on Source to convert it to its corresponding type in Destination but I am unsure how to recursively traverse the HList. My attempt is shown below in hlistEncoder
trait Converter[T] {
def convert(t:T): Datastructure
}
object Converter {
implicit object StrDatastructure extends Converter[String]{
def convert(t:String) = Datastructure.Str(t)
}
implicit object NumDatastructure extends Converter[Double]{
def convert(t :Double) = Datastructure.Num(t)
}
implicit object IncDatastructure extends Converter[Inc]{
def convert(t :Inc) = Datastructure.Incc(t)
}
implicit def SeqDatastructure[T: Converter]: Converter[Seq[T]] = new Converter[Seq[T]]{
def convert(t: Seq[T]) = {
Datastructure.Listt(t.map(implicitly[Converter[T]].convert):_*)
}
}
//HList traversals
implicit object hnilDatastructure extends Converter[HNil]{
def convert(t: HNil) = Datastructure.Hnill(t)
}
implicit def hlistEncoder[H, T <: HList](implicit
hEncoder: Converter[H],
tEncoder: Converter[T]
): Converter[H :: T] = new Converter[H :: T] {
def apply(h:H, t:T)= {
case (h :: t) => hEncoder.convert(h) ++ tEncoder.convert(t)
}
}
}
I use this method to test HList to HList conversion
def convertToDatastructureN[T](x: T)(implicit converter: Converter[T]): Datastructure = {
converter.convert(x)
}
case class Inc(i:Int)
case class Source(i: Int, n:Inc)
val x = Generic[Source]
val xHlist = x.to(Source(99, Inc(5)))
convertToDatastructureN(xHlist)
Any ideas how to implement hlistEncoder?
I guess you have
sealed trait Datastructure
object Datastructure {
case class Str(t: String) extends Datastructure
case class Num(t: Double) extends Datastructure
case class Incc(t: Inc) extends Datastructure
case class Listt(t: Datastructure*) extends Datastructure
case class Hnill(t: HNil) extends Datastructure
}
You want your type class Converter to transform T into Datastructure. But also (HList[S1:+:S2] -> HList[D1:+:D2], where I guess :: should be instead of :+:) you want subtypes of HList to be transformed into subtypes of HList (not into HList itself since otherwise Generic can't restore case class). So either you should modify your type class
trait Converter[T] {
type Out
def convert(t:T): Out
}
or you need two type classes: your original Converter and
trait HListConverter[T <: HList] {
type Out <: HList
def convert(t:T): Out
}
Moreover, currently your Converter is pretty rough. It transforms every T into Datastructure instead of into specific subtypes of Datastructure. This means Generic will be able to restore case classes only of shapes
MyClass(x: Datastructure)
MyClass(x: Datastructure, y: Datastructure)
...
Is it really what you want? If so then ok, if not and you need
MyClass(x: Str)
MyClass(x: Num, y: Incc)
...
then again you need
trait Converter[T] {
type Out
def convert(t:T): Out
}
Instead of HListConverter you can use standard shapeless.ops.hlist.Mapper.
Using scala 2.12.8 this would not compile without a cast:
trait Content
case object A extends Content
case class B(i: Int) extends Content
def asList[C <: Content](content: C): List[C] = content match {
case A => List(A) // compiles
case b: B => List(b) // does not compile
}
type mismatch;
found : b.type (with underlying type Playground.this.B)
required: C
Here's a Scastie link to the problem: https://scastie.scala-lang.org/JIziYOYNTwKoZpdCIPCvdQ
Why is working for the case object and not for the case class? How can I make it work for the case class?
EDIT
The first answers made me realize I oversimplified my problem, here's an updated version :
sealed trait Content
case object A extends Content
final case class B(i: Int) extends Content
sealed trait Container[+C <: Content]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]
object Container {
def apply[C <: Content](content: C): Container[C] = content match {
case A => ContainerA(A) // compiles
case b: B => ContainerB(b) // does not compile
}
}
Scastie link: https://scastie.scala-lang.org/TDlJM5SYSwGl2gmQPvKEXQ
C cannot be a subtype of B since B is final.
The solution is given in the comment by #lasf:
def asList[C <: Content](content: C): List[C] = content match {
case A => List(A) // compiles
case b: B => List(content) // compiles
}
The problem is that the return type is List[C] but the compiler cannot guarantee that the type of List(b) is List[C]. In particular, C could be a subtype of B in which case List(b) would List[B] which is not compatible with List[C].
The updated version can be solved using asInstanceOf, though it is not pretty.
def apply[C <: Content](content: C): Container[C] = content match {
case A => ContainerA(A) // compiles
case b: B => ContainerB(b).asInstanceOf[Container[C]]
}
Alternatively, you could take a different approach and use implicit conversion:
object Container {
implicit def contain(content: A.type): Container[A.type] = ContainerA(content)
implicit def contain(content: B): Container[B] = ContainerB(content)
}
val ca: Container[A.type] = A
val cb: Container[B] = B(0)
Or even multiple constructors:
object Container {
def apply(content: A.type): Container[A.type] = ContainerA(content)
def apply(content: B): Container[B] = ContainerB(content)
}
Here is an alternative design using a typeclass. This replaces the Content superclass with a Containable typeclass. The Container class can now contain anything as long as there is an instance of Containable for that class.
case object A
case class B(i: Int)
sealed trait Container[C]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]
trait Containable[T] {
def apply(value: T): Container[T]
}
object Containable {
implicit object AContainer extends Containable[A.type] {
def apply(value: A.type) = ContainerA(value)
}
implicit object BContainer extends Containable[B] {
def apply(value: B) = ContainerB(value)
}
}
object Container {
def apply[C](content: C)(implicit containable: Containable[C]): Container[C] =
containable(content)
}
C cannot be a subtype of B since B is final.
Wrong!
Singleton types of B instances are subtypes of B:
val b = B(0)
val container: Container[b.type] = Container[b.type](b)
Since ContainerB doesn't extend Container[b.type], it can't be returned by the last line. And it can't be changed so that it does;
case class ContainerB(content: B) extends Container[content.type]
is not legal in Scala.
Null is also a subtype of B and you can create a similar example. And so are refinement types like B { type T = Int }.
Other subtypes which are probably irrelevant because they don't have instances: Nothing, compound types like B with Iterable[Int]...
The reason why you are getting an error is because of the return type of the method is not explicit. On replacing the return type from List[C] to List[Content] solves the problem.
def asList[C <: Content](content: C): List[Content] = content match {
case A => List(A) // compiles
case b: B => List(b) // compiles
}
I have the following relations:
trait Bar[I <: Foo] { def doSomething(...) }
object Doer { def apply[I <: Foo](...)(implicit ev: Bar[I]) = ev.doSomething(...) }
trait Foo
case class A(...) extends Foo
object A { implicit object Something extends Bar[A] }
case class B(...) extends Foo
object B { implicit object SomethingElse extends Bar[B] }
I have the following situation:
val xs: List[Foo] = ...
xs.map(x => Doer(x)) // implicit not found since no implementation for type Foo.
Without using case since it will break the whole idea of having the type classes for future extensibility.
What do I need to do so that it handles this situation?
Two main difficulties can be seen in the problem
Implicits are resolved by the compiler. In places when you have abstract types but need concrete implicits you must carry your precached typeclass instances to the result code somehow.
Subtyping abstractions plays awful with typeclass-style abstractions. A lot of compromises and workarounds required to combine these.
But let imagine we have definitions like this
trait Bar[+I] {def doSomething[J >: I](x: J): String}
object Doer {
def apply[I <: Foo](el: I)(implicit ev: Bar[I]) = ev.doSomething(el)
}
trait Foo
case class A() extends Foo
object A {
implicit object Something extends Bar[A] {
def doSomething[X >: A](el: X) = "do A"
}
}
case class B() extends Foo
object B {
implicit object SomethingElse extends Bar[B] {
def doSomething[X >: B](el: X) = "do B"
}
}
We could probably create some datatype for keeping resolved implicits:
case class MemoTC[+Value, TC[+_]](value: Value)(implicit tc: TC[Value]) {
def withTC[Result](action: (Value) ⇒ TC[Value] ⇒ Result): Result =
action(value)(tc)
}
Now you can write strange code like
val xs: List[MemoTC[Foo, Bar]] = List(MemoTC(A()), MemoTC(B()))
xs.map(x => x.withTC( x ⇒ implicit bar ⇒ Doer(x) ))
If you'd like to keep your typeclass invariant, this example could be also adapted with help of existential types:
trait Bar[I] {def doSomething(x: I): String}
object Doer {
def apply[I <: Foo](el: I)(implicit ev: Bar[I]) = ev.doSomething(el)
}
trait Foo
case class A() extends Foo
object A {
implicit object Something extends Bar[A] {
def doSomething(el: A) = "do A"
}
}
case class B() extends Foo
object B {
implicit object SomethingElse extends Bar[B] {
def doSomething(el: B) = "do B"
}
}
abstract class MemoTC[Abstract, TC[_]] {
type Concrete <: Abstract
val value: Concrete
val inst: TC[Concrete]
def withTC[Result](action: (Concrete) ⇒ TC[Concrete] ⇒ Result): Result =
action(value)(inst)
}
object MemoTC {
def apply[A, C <: A, TC[_]](v: C)(implicit tc: TC[C]) = new MemoTC[A, TC] {
type Concrete = C
val value = v
val inst = tc
}
}
val xs: List[MemoTC[Foo, Bar]] = List(MemoTC(A()), MemoTC(B()))
xs.map(x => x.withTC(x ⇒ implicit bar ⇒ Doer(x)))