I'm attempting a simple exercise with shapeless' extensible records.
It's a typeclass called Projection
, which should be able to somewhat combine the functionality of Updater
and Remover
:
import shapeless._
import shapeless.tag._
import shapeless.record._
import shapeless.labelled._
import shapeless.ops.record._
import shapeless.syntax._
// Probably way too many imports
trait Projection[A <: HList, K, V] {
type B <: HList
def to(a: A, v: V): B
def from(b: B): A
}
object Projection {
type Aux[A <: HList, K, V, B0 <: HList] = Projection[A, K, V] { type B = B0 }
type Key[K] = Symbol with Tagged[K]
type F[K, V] = V with FieldType[Key[K], V]
implicit def mkProjection[A <: HList, K, V, B0 <: HList](implicit
keyWitness: Witness.Aux[K],
updater: Updater.Aux[A, F[K, V], B0],
remover: Remover.Aux[B0, K, (V, A)]
): Projection.Aux[A, K, V, B0] = new Projection[A, K, V] {
type B = B0
def from(b: B0): A = b - keyWitness
def to(a: A, v: V): B0 = a + field[Key[K]](v)
}
}
My rather simple test
import Projection._
val thirdFieldWitness = Witness("thirdField")
val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
unfortunately fails with the error
could not find implicit value for parameter e: Projection[shapeless.HNil,ProjectionSpec.this.thirdFieldWitness.T,Boolean]
[error] val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
-Xlog-implicits
shows the reason for it:
ProjectionSpec.scala:18:35: record.this.Remover.mkRemover is not a valid implicit value for shapeless.ops.record.Remover.Aux[Boolean with shapeless.labelled.FieldType[Projection.Key[ProjectionSpec.this.thirdFieldWitness.T],Boolean] :: shapeless.HNil,ProjectionSpec.this.thirdFieldWitness.T,(Boolean, shapeless.HNil)] because:
[info] hasMatchingSymbol reported error: No field String("thirdField") in record type Boolean with shapeless.labelled.FieldType[Projection.Key[ProjectionSpec.this.thirdFieldWitness.T],Boolean] :: shapeless.HNil
[info] val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
Please help me understand this message and show me how to fix it.
Is there possibly an easier way to do this kind of extension and shortening of labelled generics?