I'm having trouble understanding how Shapeless record selector interacts with the scala output type. I am trying to create a method that can capture a field from a Shapeless record by key only if the field value has a certain unary type constructor, in this particular case Vector[_] , and then capture the internal value of the output type V from Vector , in this case with Vector.apply() .
I feel like I'm around. This works with a specific Int type:
val record = ( "a" ->> Vector(0,2,4) ) :: ( "b" ->> Set(1,3,5) ) :: HNil def getIntFromVectorField[L <: HList](l: L, fieldName:Witness, index:Int)(implicit sel: Selector.Aux[L, fieldName.T, Vector[Int]] ):Int = l(fieldName).apply(index) getIntFromVectorField(record,"a",1) // Returns 1 getIntFromVectorField(record,"b",0) // Does not compile, as intended
But if I try to make a conclusion about the internal type, this will not work:
def getValueFromVectorField[L <: HList,V](l:L, fieldName:Witness, index:Int)(implicit sel: Selector.Aux[L,fieldName.T,Vector[V]] ):V = l(fieldName).apply(index) // Compiles getValueFromVectorField(record,"a",1) // Why does this not compile?
Here's the complete error:
could not find implicit value for parameter sel: shapeless.ops.record.Selector[shapeless.::[scala.collection.immutable.Vector[Int] with shapeless.labelled.KeyTag[String("a"),scala.collection.immutable.Vector[Int]], shapeless.::[scala.collection.immutable.Set[Int] with shapeless.labelled.KeyTag[String("b"),scala.collection.immutable.Set[Int]], shapeless.HNil]],String("a")]{type Out = scala.collection.immutable.Vector[V]}
What I was able to do is the following:
def getValueFromVectorField[L <: HList,T,V](l:L, fieldName:Witness, index:Int)(implicit sel: Selector.Aux[L,fieldName.T,T], unpack: Unpack1[T,Vector,V] ):V = l(fieldName) match { case v:Vector[V] => v.apply(index) } getValueFromVectorField(record,"a",1) // Returns 1, Yay! getValueFromVectorField(record,"b",0) // Does not compile, as intended
What should be safe, huh? But pattern matching does not seem very idiomatic for the formless, and I wonder why a more concise approach with inference does not work. Is there a cleaner way to do this?