Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala, getting the type parameters of a KList as an HList

Suppose I have an abitrary KList, which for the sake of argument has type constructor Option[_], ie;

type Example = Option[Int] :: Option[String] :: HNil

Is there a way I can retrieve an Hlist made of the type parameters?

type Params = Int :: String :: HNil

So, for example I might be able to define some sort of arbitrary getOrElse method

getOrElse(ex:Example, default:Params):Params

Now I'm looking for something possibly of a form like this (or similar as the type structure I propose might not be feasible).

case class MyOptionList[L <: HList](maybes:L) {
  type Concrete = {somehow the hlist params types as an Hlist}
  def getOrElse(default:Concrete):Concrete = ???

}
like image 247
J Pullar Avatar asked Dec 29 '14 13:12

J Pullar


1 Answers

I'm not Miles, but it's possible to accomplish what you're trying to do pretty elegantly with Shapeless's Comapped:

import shapeless._, ops.hlist.Comapped

case class MyOptionList[L <: HList, C <: HList](maybes: L)(
  implicit val comapped: Comapped.Aux[L, Option, C]
) {
  def getOrElse(default: C): C = default // Not a useful implementation
}

And then:

scala> val x: Int :: HNil = MyOptionList(Option(1) :: HNil).getOrElse(2 :: HNil)
x: shapeless.::[Int,shapeless.HNil] = 2 :: HNil

Note that in some cases it can be more convenient to put the constraint on the method:

case class MyOptionList[L <: HList](maybes: L) {
  def getOrElse[C <: HList: ({ type l[x] = Comapped.Aux[L, Option, x] })#l](
    default: C
  ): C = default
}

Here the usage is the same, but you don't have the extra type parameter on the case class. If you want to use this approach but constrain the creation of MyOptionList to disallow non-Option members, you could use L <: HList: *->*[Option]#λ in its type parameter list.

like image 122
Travis Brown Avatar answered Nov 15 '22 17:11

Travis Brown