shapeless: Generic programming for Scala | This room deprecated in favour of #shapeless on the Typelevel Discord: https://discord.gg/bSQBZA3Ced
joroKr21 on main
Update sbt-mima-plugin to 1.1.0 Merge pull request #1258 from s… (compare)
joroKr21 on main
Update sbt-scalajs, scalajs-com… Merge pull request #1257 from s… (compare)
joroKr21 on v2.3.9
joroKr21 on 2.3
When case class has custom unap… Merge pull request #1256 from j… (compare)
joroKr21 on main
When case class has custom unap… Merge pull request #1255 from j… (compare)
Poly
, one with custom typeclasses
Poly
, it's shorter
Poly
exposes type class instances (Case
), which you can use in your typeclass derivation
Poly
, you can ask for an implicit Case1
of that Poly
Case1
, Case2
...what have you)
TIL:
No, the subclass rule and the specificity of the type rule are both run and the score is tallied. If they are in opposite directions, it ends up with ambiguity.
So prioritising implicits to encode typelevel pattern matching precedence does not always work...disappointing
OT: can i get a Generic
for a trait
with only abstract fields? e.g. with a structure like this:
trait Foo { def a: A; def b: B; def c: C }
trait Bar extends Foo { def d: D }
trait Baz extends Foo { def e: E }
I want to be able to get Generic
s for Foo
/Bar
/Baz
.
The context is that I'm trying to have multiple classes/traits share a set of fields while also being able to get a Generic
for them, without having to repeat all the fields everywhere. trait
s can be composed to allow this but but classes/fields/ctor-args can't. cf. https://github.com/alexarchambault/case-app/issues/58#issuecomment-313799457
Generic
s for case class
es would be useful too; iirc it hangs off of the existence of a case class
's apply
method?
case class Foo(a: String, b: Bar)
case class Bar(c: Int, d: Baz)
case class Baz(e: Long)
val v = Foo("A", Bar(1, Baz(2)))
def a = flatten(v)
res1: shapeless.::[String with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("a")],String],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Int],shapeless.::[Long with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("e")],Long],shapeless.HNil]]] =
A :: 1 :: 2 :: HNil
Poly
f
, I can implicitly ask for an instance of that poly for type parameter A
by implicit ev: Case[A, f.type]
.f
with another poly g
via object c extends Compose(f, g)
. How do I implicitly ask for an instance of the composed poly for type parameter A
?
import shapeless._, ops.hlist._, poly._, labelled._
trait Describe[A] {
def apply(a: A): String
}
object Describe {
def apply[A](a: A)(implicit ev: Describe[A]) = ev(a).dropRight(2)
implicit def all[A](
implicit f: Case.Aux[body.type, A :: HNil, String]): Describe[A] =
new Describe[A] {
def apply(a: A) = f.apply(a)
}
object body extends Compose(describer, flatten)
object describer extends LowPrioDescriber {
implicit def all[H <: HList](
implicit fm: MapFolder[H, String, describer.type]) =
at[H](x => fm(x, "", _ + _))
}
trait LowPrioDescriber extends Poly1 {
implicit def base[K <: Symbol, V](implicit key: Witness.Aux[K]) =
at[FieldType[K, V]](x => s"${key.value.name} = ${x.toString}, ")
}
object flatten extends LowPrioFlatten {
implicit def hlists[H <: HList](
implicit fm: Lazy[FlatMapper[flatten.type, H]]) =
at[H](x => fm.value(x))
implicit def kv[K, V, R](implicit gen: LabelledGeneric.Aux[V, R],
rec: Lazy[Case1[flatten.type, R]]) =
at[FieldType[K, V]](x => rec.value(gen.to(x)))
implicit def prods[A, R <: HList](
implicit gen: LabelledGeneric.Aux[A, R],
rec: Lazy[Case1[flatten.type, R]]) =
at[A](x => rec.value(gen.to(x)))
}
trait LowPrioFlatten extends Poly1 {
implicit def all[A] = at[A](x => x :: HNil)
}
}
case class Foo(a: String, b: Bar)
case class Bar(c: Int, d: Baz)
case class Baz(e: Long)
val v = Foo("A", Bar(1, Baz(2)))
def c = Describe(v)
// res1: String = a = A, c = 1, e = 2