Shapeless Type Conversion

I have a class like this:

class MyClass[T <: HList] { val x: ??? } 

My problem is the type x val. I would like it to be an HList with every type of U T HList replaced by Option[U] . That is, if I specify:

 new MyClass[Int :: String :: HNil] 

I would like x be of type Option[Int] :: Option[String] :: HNil

Is it possible? How to do it?

+6
source share
1 answer

You will need a Mapped instance that will witness that T and type x have this relationship:

 import shapeless._, ops.hlist.Mapped abstract class MyClass[T <: HList, OT <: HList](implicit mapped: Mapped.Aux[T, Option, OT] ) { val x: OT } 

Unfortunately, this is inconvenient to instantiate:

 new MyClass[Int :: String :: HNil, Option[Int] :: Option[String] :: HNil] { val x = Some(0) :: Some("") :: HNil } 

There are ways around this, but they require additional changes. For example, you can enable the output of two parameters of the type:

 import shapeless._, ops.hlist.Comapped class MyClass[T <: HList, OT <: HList](val x: OT)(implicit mapped: Comapped.Aux[OT, Option, T] ) 

And then:

 new MyClass(Option(0) :: Option("") :: HNil) 

Or you can use something closer to your source class using a special constructor in the companion object:

 import shapeless._, ops.hlist.Mapped abstract class MyClass[T <: HList] { type OT <: HList def mapped: Mapped.Aux[T, Option, OT] val x: OT } object MyClass { class PartiallyApplied[T <: HList] { def apply[OT0 <: HList](x0: OT0)(implicit mapped0: Mapped.Aux[T, Option, OT0] ): MyClass[T] = new MyClass[T] { type OT = OT0 val mapped: Mapped.Aux[T, Option, OT] = mapped0 val x: OT = x0 } } def apply[T <: HList]: PartiallyApplied[T] = new PartiallyApplied[T] } 

And then:

 MyClass[Int :: String :: HNil](Option(0) :: Option("") :: HNil) 

Which of these approaches is more appropriate will depend on how you use the class.

+9
source

All Articles