trait C { type M type A val upt: A => M => M }
object C1 extends C {
case class M(s: String)
case class A(c: Char)
val upt: A => M => M = { case A(c) => m => m copy (s = m.s + c) }
}
object C2 extends C {
case class M(l: Long)
case class A(i: Int)
val upt: A => M => M = { case A(i) => m => m copy (l = m.l + i) }
}
class CS(val cSubs: Seq[C]) extends C {
case class M(mSubs: Seq[C#M])
sealed trait A
case class Asub[A0 <: C#A](idx: Int, aSub: A0) extends A
val upt: A => M => M = {
case Asub(idx, aSub) =>
m => m copy (mSubs = m.mSubs.zip(cSubs).zipWithIndex map {
case ((mSub, cSub), `idx`) => cSub.upt(aSub.asInstanceOf[cSub.A])(mSub.asInstanceOf[cSub.M])
case ((mSub, cSub), _) => mSub
})
}
}
Don't wonder where the Asub(idx, aSub) instances finally come from, this is a minimized example.
For example I can run the following lines:
val c1m1 = C1.M("Hey")
val c1m2: C1.M = C1.upt(C1.A('!'))(c1m1)
val cs = new CS(Seq(C1, C2))
val csm1 = cs.M(Seq[C#M](C1.M("Hey"), C2.M(42L)))
cs.upt(cs.Asub(0, C1.A('!')))(csm1)
cs.upt(cs.Asub(1, C2.A(8)))(csm1)
But how can I use a HList instead of a Seq to get rid of this instanceOf? I tried but failed. I started with ensuring that every element in an argument HList conforms to type C:
trait ConformsTo[L <: HList, T]
object ConformsTo {
implicit def hnil[X]: HNil ConformsTo X = null
implicit def cons[X, X0 <: X, T <: HList](implicit ev: T ConformsTo X): (X0 :: T) ConformsTo X = null
}
object CS {
def apply[L <: HList](l: L)(implicit conforms: L ConformsTo C) = new CS(l)
}
class CS[L <: HList](val l: L) extends C { ... }
Now I got stuck with mapping and zipWithIndex and modelling case class Asub(nat: Nat, ...) ....
I appreciate any ideas.
Thank you!
Peter