Type inference on contents of shapeless HList
hlist, scala, shapeless
Solution
Shapeless provides a `ToList` implicit which is used, unsurprisingly, to convert HLists to Lists.
In order to do that, it must first calculate the LUB (least upper bound) of the types in the HList, and that's something you can use:
import shapeless.ops.hlist.ToList
class Mappings[L <: HList, Lub](mappings:L)(implicit toList: ToList[L, Lub]) {
...
}
`L` goes in, implicit resolution discovers the one (and only) valid `ToList` instance constrained by that `L`, the `Lub` type of which is pulled out.
That's not enough though, as `Lub` will be `KeyMapping[String]`, whereas all you want is the `String` part. As usual with shapeless, the solution is to add another implicit:
class Mappings[L <: HList, Lub, KeyType](mappings:L)(
implicit
val toList: ToList[L, Lub],
val kt: Lub <:< KeyMapping[KeyType]
) {
val k: KeyType = null.asInstanceOf[KeyType]
}
(the implicits don't need to be `val`s, but it helps if they are when you're exploring things in the REPL)
What this asserts is that `Lub` corresponds to the type `KeyMapping[KeyType]` (e.g. it's a subtype or the exact same type), where `KeyType` is, as yet, unknown. Again, there's only one valid solution to the constraints specified, and the `KeyType` parameter is pulled out as being `String`.
I have no idea how you plan on implementing `k`, but you may find that having that `toList` instance helps you to do so, as it allows you to now invoke `mappings.toList`
Problem
This example is simplified. I have a set of classes like this: ``` case class KeyMapping[KeyType](k:KeyType) class WrappedMapping[KeyType](m:T forSome {type T <: KeyMapping[KeyType]}) { val k:KeyType = ??? } ``` In the following code the types are correctly inferred: ``` val w = new WrappedMapping(KeyMapping("key")) //The statement below gives the correct error //type mismatch; // found : w.k.type (with underlying type String) required: Nothing //val test1:Nothing = w.k ``` I have no clue how to infer the type correctly for the following: ``` class Mappings[KeyType, L <: HList](mappings:L) { val k:KeyType = ??? } val m = new Mappings(KeyMapping("key1") :: KeyMapping("key2") :: HNil) // should not compile, k should be of type String val test2:Nothing = m.k ``` Is there a way I can infer the `KeyType` based on the contents of the `HList`?