I am trying to create a type class that will allow me to increment an Int field called "counter" on any case class, as long as that class has such a field.
I have tried to do this with Shapeless but am hitting walls (after first trying to digest "The Type Astronaut's Guide to Shapeless", the "Feature overview" of Shapeless 2.0.0 and numerous threads on Stack Overflow).
What I want is to be able to do something like
case class MyModel(name:String, counter:Int) {}
val instance = MyModel("Joe", 4)
val incremented = instance.increment()
assert(incremented == MyModel("Joe", 5))
And it should work for any case class with a suitable counter field.
I thought that this would be possible using a type class and Shapeless' record abstraction (and an implicit conversion to get the increment functionality added as a method). The bare bones would be something like this:
trait Incrementer[T] {
def inc(t:T): T
}
object Incrementer {
import shapeless._ ; import syntax.singleton._ ; import record._
implicit def getIncrementer[T](implicit generator: LabelledGeneric[T]): Incrementer[T] = new Incrementer[T] {
def inc(t:T) = {
val repr = generator.to(t)
generator.from(repr.replace('counter, repr.get('counter) + 1))
}
}
}
However, this does not compile. The error being value replace is not a member of generator.Repr. I guess this is because the compiler does not have any guarantee as to T having a field called counter and it being of type Int. But how could I tell it so? Is there better/more documentation on Shapeless' record? Or is this a completely wrong way to go?
You have to just implicitly require a Modifier
import shapeless._
import ops.record._
implicit class Incrementer[T, L <: HList](t: T)(
implicit gen: LabelledGeneric.Aux[T, L],
modifier: Modifier.Aux[L, Witness.`'counter`.T, Int, Int, L]
) {
def increment(): T = gen.from(modifier(gen.to(t), _ + 1))
}
You can easily do it with a simple typeclass derivation:
trait Incrementer[T] {
def inc(s: Symbol)(t: T): T
}
object Incrementer {
def apply[T](implicit T: Incrementer[T]): Incrementer[T] = T
implicit def head[Key <: Symbol, Head, Tail <: HList](implicit Key: Witness.Aux[Key], Head: Numeric[Head]) = new Incrementer[FieldType[Key, Head] :: Tail] {
import Head._
override def inc(s: Symbol)(t: FieldType[Key, Head] :: Tail): (FieldType[Key, Head] :: Tail) =
if (s == Key.value) (t.head + fromInt(1)).asInstanceOf[FieldType[Key, Head]] :: t.tail
else t
}
implicit def notHead[H, Tail <: HList](implicit Tail: Incrementer[Tail]) = new Incrementer[H :: Tail] {
override def inc(s: Symbol)(t: H :: Tail): H :: Tail = t.head :: Tail.inc(s)(t.tail)
}
implicit def gen[T, Repr](implicit gen: LabelledGeneric.Aux[T, Repr], Repr: Incrementer[Repr]) = new Incrementer[T] {
override def inc(s: Symbol)(t: T): T = gen.from(Repr.inc(s)(gen.to(t)))
}
}
case class Count(counter: Int)
case class CountAndMore(more: String, counter: Int)
case class FakeCount(counter: Long)
object Test extends App {
println(Incrementer[Count].inc('counter)(Count(0)))
println(Incrementer[CountAndMore].inc('counter)(CountAndMore("", 0)))
println(Incrementer[FakeCount].inc('counter)(FakeCount(0)))
}
Related
I want to write a type class, to add some behavior to a generic type. However, I cannot figure out how to do it; I keep running into the error below.
Imagine you have a generic type MyList[A]:
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
Now you want to add some behavior to this class, e.g. to convert it into a Stream[A]. A type class based extension would seem appropriate:
// inspired by https://scalac.io/typeclasses-in-scala
trait MyListExt[T, A <: MyList[T]] {
def stream(a: A): Stream[T]
}
object MyListExt {
def apply[T, A <: MyList[T]](implicit a: MyListExt[T, A]): MyListExt[T, A] = a
object ops {
implicit class MyListExtOps[T, A <: MyList[T]](val a: A) extends AnyVal {
def stream(implicit ext: MyListExt[T, A]): Stream[T] = ext.stream(a)
}
}
private type T0
implicit val myListToStreamImpl: MyListExt[T0, MyList[T0]] = new MyListExt[T0, MyList[T0]] {
override def stream(a: MyList[T0]): Stream[T0] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
When I now try to use this type class in my code, I get the following error at l.stream:
No implicits found for parameter ext: MyListExt[T_, MyList[Int]]
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
What am I doing wrong, or how can I get my l.stream to work?
I have seen many examples involving type classes and implicit conversion, but none so far operating on generic types.
implicit def myListToStreamImpl[T]: MyListExt[T, MyList[T]] = new MyListExt[T, MyList[T]] {
override def stream(a: MyList[T]): Stream[T] = {
def fold(l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty[T1])
}
}
Your types don't align because you've used that private type for whatever bizarre reason. Types nested inside objects have a completely different application, and they don't relate to your current use case.
The trouble is that in l.stream.foreach(println) the l is implicitly transformed to new MyListExt.ops.MyListExtOps[.., ..](l) and generics are inferred to be [Nothing, MyList[Int]], which doesn't satisfy [T, A <: MyList[T]].
I can't see reason to parametrize MyListExt with both T and A <: MyList[T]. I guess T is enough, use MyList[T] instead of A.
Don't use private type T0, just parametrize myListToStreamImpl (make it def) with T0 aka T.
Try
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
trait MyListExt[T] {
def stream(a: MyList[T]): Stream[T]
}
object MyListExt {
def apply[T](implicit a: MyListExt[T]): MyListExt[T] = a
object ops {
implicit class MyListExtOps[T](val a: MyList[T]) extends AnyVal {
def stream(implicit ext: MyListExt[T]): Stream[T] = ext.stream(a)
}
}
implicit def myListToStreamImpl[T]: MyListExt[T] = new MyListExt[T] {
override def stream(a: MyList[T]): Stream[T] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
I am trying to find an elegant way to do the following.
Let's assume we have the following classes:
case class Foo(fooName: String, bar: Bar, baz: Baz)
case class Bar(barName: String, baz: Baz)
case class Baz(bazName: String)
I want to be able to change the name (in this case of Foo and its children objects in some way), for example, to prefix them with some title.
I might define a typeclass which serves that purpose:
trait Titled[T] {
def titled(t: T)(title: String): T
}
For Foo, the implementation would do this:
implicit val fooTitled: Titled[Foo] = new Titled[Foo] {
def titled(foo: Foo)(title: String): Foo = foo.copy(fooName = title + fooName)
}
There could be other implementations, such as Esquired, which would suffix the name with "Esq."
But this does not update the title of the children values, bar and baz, which I would like.
What I'd eventually like to end up with is something like this:
//import all the implicits needed
val foo = Foo(...)
val titledFoo = foo.title("Mr. ") // names are prefixed with Mr.
val andEsquired = foo.esquire // names are also suffixed with Esq
Now, I've been looking online to see if it is possible to do, and I've seen shapeless library, but I'm still not on that level of Scala knowledge that I could decipher and create such "magic" if its even possible.
I am not necessarily looking for a complete solution (although I would appreciate one), but if someone could point me in the right direction, show me some examples, tutorials or whatever on things like these, I'd be very grateful.
Try the following type class. I assume that all case classes that should have type class instance have the first field of type String to be prefixed.
import shapeless.ops.hlist.IsHCons
import shapeless.{::, Generic, HList, HNil}
trait Titled[T] {
def titled(t: T)(title: String): T
}
object Titled {
//implicit def identity[A]: Titled[A] = new Titled[A] {
// override def titled(t: A)(title: String): A = t
//}
implicit def transform[A <: Product, L <: HList, H, T <: HList](implicit
generic: Generic.Aux[A, L],
isHCons: IsHCons.Aux[L, String, T],
tailTitled: HListTitled[T]): Titled[A] = new Titled[A] {
override def titled(t: A)(title: String): A = {
val l = generic.to(t)
val head = isHCons.head(l)
val tail = isHCons.tail(l)
val newHead = title + head
val newTail = tailTitled.titled(tail)(title)
val newL = isHCons.cons(newHead, newTail)
generic.from(newL)
}
}
}
trait HListTitled[L <: HList] {
def titled(t: L)(title: String): L
}
object HListTitled {
implicit val hnil: HListTitled[HNil] = new HListTitled[HNil] {
override def titled(t: HNil)(title: String): HNil = HNil
}
implicit def hcons[H, T <: HList](implicit
headTitled: Titled[H],
tailTitled: HListTitled[T]): HListTitled[H :: T] = new HListTitled[H :: T] {
override def titled(t: H :: T)(title: String): H :: T =
headTitled.titled(t.head)(title) :: tailTitled.titled(t.tail)(title)
}
}
implicit class TitledOps[T](t: T) {
def titled(title: String)(implicit ttld: Titled[T]): T = ttld.titled(t)(title)
}
case class Foo(fooName: String, bar: Bar, baz: Baz)
case class Bar(barName: String, baz: Baz)
case class Baz(bazName: String)
case class Foo1(fooName: String, bar: Bar, baz: Baz, i: Int)
Foo("Johnson", Bar("Smith", Baz("Doe")), Baz("James")).titled("Mr. ")
// Foo(Mr. Johnson,Bar(Mr. Smith,Baz(Mr. Doe)),Baz(Mr. James))
Foo1("Johnson", Bar("Smith", Baz("Doe")), Baz("James"), 10).titled("Mr. ")
// doesn't compile
// if you want it to compile uncomment "identity"
I'm working on a generic conversion library and I'd like to add automatic typeclass derivation using shapeless. It works in the general case but I'd like to introduce Haskellesque newtypes with automatic unwrapping and so I'd like to specialize the deriving function for my NewType type but scalac still picks up the more generic implicit value. Here's the code so far:
import shapeless._, shapeless.syntax._
trait NewType[A] { val value: A }
sealed trait ConversionTree
case class CInt(value: Int) extends ConversionTree
case class CBoolean(value: Boolean) extends ConversionTree
case class CString(value: String) extends ConversionTree
case class CArray(value: List[ConversionTree]) extends ConversionTree
case class CObject(values: Map[String, ConversionTree]) extends ConversionTree
def mergeCObjects(o1: CObject, o2: CObject): CObject = CObject(o1.values ++ o2.values)
trait ConvertsTo[A] {
def convertTo(value: A): ConversionTree
}
object ConvertsTo {
implicit val intConverter = new ConvertsTo[Int] { ... }
implicit val boolConverter = new ConvertsTo[Boolean] { ... }
implicit val stringConverter = new ConvertsTo[String] { ... }
implicit def arrayConverter[A](implicit convertInner: ConvertsTo[A]) = new ConvertsTo[List[A]] { ... }
implicit def objectConverter[A](implicit convertInner: ConvertsTo[A]) = new ConvertsTo[Map[String, A]] { ... }
implicit def newTypeConverter[A](implicit convertInner: ConvertsTo[A]): ConvertsTo[NewType[A]] = new ConvertsTo[NewType[A]] {
override def convertTo(value: NewType[A]): ConversionTree = {
convertInner.convertTo(value.value)
}
}
implicit def deriveHNil: ConvertsTo[HNil] = new ConvertsTo[HNil] {
override def convertTo(value: HNil): ConversionTree = CObject(Map[String, ConversionTree]())
}
// This is the generic case
implicit def deriveHCons[K <: Symbol, V, T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, V] :: T] = new ConvertsTo[FieldType[K, V] :: T]{
override def convertTo(value: FieldType[K, V] :: T): ConversionTree = {
val head = sv.value.convertTo(value.head)
val tail = st.value.convertTo(value.tail)
mergeCObjects(CObject(Map(key.value.name -> head)), tail.asInstanceOf[CObject])
}
}
// This is the special case for NewTypes
implicit def deriveHConsNewType[K <: Symbol, V, T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, NewType[V]] :: T] = new ConvertsTo[FieldType[K, NewType[V]] :: T] {
override def convertTo(value: FieldType[K, NewType[V]] :: T): ConversionTree = {
val head = sv.value.convertTo(value.head.value)
val tail = st.value.convertTo(value.tail)
mergeCObjects(CObject(Map(key.value.name -> head)), tail.asInstanceOf[CObject])
}
}
implicit def deriveInstance[F, G](implicit gen: LabelledGeneric.Aux[F, G], sg: Lazy[ConvertsTo[G]]): ConvertsTo[F] = {
new ConvertsTo[F] {
override def convertTo(value: F): ConversionTree = sg.value.convertTo(gen.to(value))
}
}
}
def convertToG[A](value: A)(implicit converter: ConvertsTo[A]): ConversionTree = converter.convertTo(value)
case class Id(value: String) extends NewType[String]
case class User(id: Id, name: String)
println(s"${ConvertsTo.newTypeConverter[String].convertTo(Id("id1"))}")
println(s"User: ${convertToG(User(Id("id1"), "user1"))}")
Output of the first println: CString("id1")
Output of the second println: CObject(Map("id" -> CObject(Map("value" -> CString("id1"))), "name" -> CString("user1")))
I'd like to get rid of the extra CObject around the id field in the second println. As you can see, calling the newTypeConverter directly results in the correct output but it doesn't work when the NewType is embedded in an object(and if I put a breakpoint in the deriveHConsNewType.convertTo method I can verify that it doesn't get called).
I've tried to define deriveHConsNewType like this as well but it didn't help:
implicit def deriveHConsNewType[K <: Symbol, V, N <: NewType[V], T <: HList](
implicit
key: Witness.Aux[K],
sv: Lazy[ConvertsTo[V]],
st: Lazy[ConvertsTo[T]]
): ConvertsTo[FieldType[K, N] :: T] = new ConvertsTo[FieldType[K, N] :: T] { ... }
Can someone explain me how the implicit search works when this kind of overlap occurs and provide a solution to my problem?
EDIT: Solved the issue by making the type variable of ConvertsTo contravariant, scalac now picks the specialized implicit value.
Solved the issue by making the type variable of ConvertsTo contravariant, scalac now picks the specialized implicit value.
trait ConvertsTo[-A] {
def convertTo(value: A): ConversionTree
}
In my application I have multiple case classes and objects which are part of sealed trait hierarchy. I use them as messages in Akka.
Those classes need to be converted to user friendly form before sending through websocket.
Previously I used big pattern match to convert them in single place, but as number of types grows I would like to use implicit conversion:
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
trait Converter[T] {
def convert(t: T): Int
}
}
object Implicits {
import Types._
implicit object Type1Coverter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Coverter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
implicit object Type3Coverter extends Converter[SubType3.type] {
override def convert(t: SubType3.type): Int = 3
}
}
object Conversion {
import Types._
def convert[T: Converter](t: T): Int = {
implicitly[Converter[T]].convert(t)
}
def convert2[T <: Type](t: T)(implicit ev1: Converter[SubType1.type], ev2: Converter[SubType2.type], ev3: Converter[SubType3.type]): Int = {
t match {
case t1#SubType1 =>
implicitly[Converter[SubType1.type]].convert(t1)
case t2#SubType2 =>
implicitly[Converter[SubType2.type]].convert(t2)
case t3#SubType3 =>
implicitly[Converter[SubType3.type]].convert(t3)
}
}
}
I would like to use them as follow:
import Types._
import Conversion._
import Implicits._
val t1 = SubType1
val x1: Int = convert(t1)
val t: Type = SubType2 // T is of type Type
//Is it possible to handle that?
//val x: Int = convert(t)
val y: Int = convert2(t)
I would love to know if there is any "magic" way to generate something like convert2 automatically without writing a macro. Maybe there is already a library which provides macro like this?
Since you have no info at compile time about t's type, you have to work at runtime.
if you put your Converters in a sealed family, you could do something like the follwing, using a technique explained in this question:
import shapeless._
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
tsc: AllSingletons[A, T],
witness: Witness.Aux[H]): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
}
trait EnumerableAdt[A] {
def values: Set[A]
}
object EnumerableAdt {
implicit def fromAllSingletons[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]): EnumerableAdt[A] =
new EnumerableAdt[A] {
def values = singletons.values.toSet
}
}
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
sealed abstract class Converter[T <: Type: ClassTag] {
def convert(t: T): Int
def convertibleObjectClass = implicitly[ClassTag[T]].runtimeClass
}
object Implicits {
implicit object Type1Converter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Converter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
// let's pretend you FORGOT to add Type3Converter
// implicit object Type3Converter extends Converter[SubType3.type] {
// override def convert(t: SubType3.type): Int = 3
// }
}
}
object Conversion {
import Types._
val AllConverters: Map[Class[_], Converter[_ <: Type]] = implicitly[EnumerableAdt[Converter[_ <: Type]]].values
.map(c => c.convertibleObjectClass -> c).toMap
// You're sure you have all the converters here but you can't be sure you remembered to add one per subtype... you have to test it
// you are sure this cast doesn't fail anyway because of how you created the map
def findConverter[T <: Type](t: T) = AllConverters.get(t.getClass).asInstanceOf[Option[Converter[T]]]
def convert2[T <: Type](t: T): Option[Int] = findConverter(t).map(_.convert(t))
}
object Test extends App {
import Types._
import Conversion._
val t: Type = SubType2
val t2: Type = SubType3
// works, because a Converter[Subtype2.type] exists
val a: Option[Int] = convert2(t)
// returns None, because a Converter[Subtype3.type] doesn't exist
val b: Option[Int] = convert2(t2)
}
I have a sealed trait/abstract class hierarchy and need to convert its subtypes to strings and these strings back to the types. This code example describes what I want to achieve:
import shapeless._
object Test extends App {
sealed abstract class C(val i: Int)
case object O1 extends C(1)
case object O2 extends C(2)
// lots of other implementations
trait TC[A] {
def f: String
}
implicit object TC1 extends TC[O1.type] {
def f = "O1"
}
implicit object TC2 extends TC[O2.type] {
def f = "O2"
}
object fqn {
val o1 = implicitly[TC[O1.type]].f
val o2 = implicitly[TC[O2.type]].f
def asString(c: C): String = c match {
case O1 ⇒ o1
case O2 ⇒ o2
}
def fromString(s: String): C = s match {
case `o1` ⇒ O1
case `o2` ⇒ O2
}
}
object asString extends Poly1 {
private implicit def impl[A <: C : TC] = at[A](a ⇒ implicitly[TC[A]].f)
def apply(c: C): String = Generic[C].to(c).map(this).unify
}
object fromString {
def apply(s: String): C = ???
}
// This works as expected
println(O1 eq fqn.fromString(fqn.asString(O1)))
println(O2 eq fqn.fromString(fqn.asString(O2)))
// Does not yet work
println(O1 eq fromString(asString(O1)))
println(O2 eq fromString(asString(O2)))
}
Right now, everything works fine with the functionality in fqn, but it is cumbersome and difficult to maintain for more subtypes of C. With shapeless I managed to get away with the asString part but I'm stuck in finding a solution for the fromString part.
Can anyone think of a way in shapeless (or another library) to implement the fromString part?
Some more details about my example:
TC is provided by a library, I can't change it. The typeclasses are
generated by macros in this library, therefore the TCN type classes
don't directly exist.
I can't easily provide a macro that generates the implementation of fqn.asString and fqn.fromString, therefore I'm looking for a library that already supports this behavior.
Unfortunately I don't know how to solve your problem in compile time with macros\shapeless magic. But in run time the solution could be:
import reflect.runtime.{currentMirror => cm}
import scala.reflect.runtime.universe._
def fromString(s: String): C = {
val caseObjects = weakTypeOf[C].baseClasses.
flatMap(s => s.asClass.knownDirectSubclasses)
val map = caseObjects.map(obj => (obj.name.toString, obj)).toMap
cm.reflectModule(map(s).companionSymbol.asModule).instance match {
case c: C => c
}
}
Maybe you have to add isModule conditions to get only case objects.
I managed to come up with a solution:
import shapeless._
object GetAllSingletons {
sealed trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
witness: Witness.Aux[H],
tsc: AllSingletons[A, T]
): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
final class GetAllSingletones[A] {
def apply[C <: Coproduct]()(implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]
): List[A] =
singletons.values
}
def singletons[A] = new GetAllSingletones[A]
}
object Test extends App {
sealed abstract class C(val i: Int)
case object O1 extends C(1)
case object O2 extends C(2)
// lots of other implementations
trait TC[A] {
def f: String
}
implicit object TC1 extends TC[O1.type] {
def f = "O1"
}
implicit object TC2 extends TC[O2.type] {
def f = "O2"
}
object asString extends Poly1 {
private implicit def impl[A <: C : TC] = at[A](a ⇒ implicitly[TC[A]].f)
def apply(c: C): String = Generic[C].to(c).map(this).unify
}
object fromString {
val singletons: Map[String, C] = GetAllSingletons.singletons[C]().map(s ⇒ asString(s) → s)(collection.breakOut)
def apply(s: String): C = singletons(s)
}
println(O1 eq fromString(asString(O1)))
println(O2 eq fromString(asString(O2)))
}
The definitions in GetAllSingletons are cumbersome, but I couldn't find a way to simplify it further. The idea comes from this question. Another question has an answer that provides a simpler solution, but it only works in a more limited way.