bbarker
bbarker

Reputation: 13138

How to get the parameter of a type constructor in Scala?

I'm looking for a way to "unwind" type aliases.

In the following example, only 'O' has a type alias defined in the second type aliasing line.

type CodebookDetails = List[(String, List[String])]
type O[I] = CodebookDetails
requestDecodeIterable[I, O](request)

Is it possible to get I in a similar way, or does one just have to copy and paste types like this?:

requestDecodeIterable[(String, List[String]), List](request)

Upvotes: 1

Views: 77

Answers (1)

HTNW
HTNW

Reputation: 29193

You could use shapeless's the macro:

// Typelevel function unapplies unary type constructors:
// F[A] => (F, A)
// I think I recall seeing it somewhere in shapeless, but I can't find it,
// so I implemented it myself
sealed trait Unapp1[T] { type F[_]; type A; implicit def eq: F[A] =:= T }
object Unapp1 {
  type Aux[T0, F0[_], A0] = Unapp1[T0] { type F[X] = F0[X]; type A = A0 }
  implicit def source[F0[_], A0]: Aux[F0[A0], F0, A0] = new Unapp1[F0[A0]] {
    type F[X] = F0[X]
    type A = A0
    override def eq: F[A] =:= F0[A0] = implicitly
  }
  def apply[T](implicit unapp: Unapp1[T]): unapp.type = unapp
}

// the.`tpe` looks up the implicit value of type tpe and gives it a stable path
// suitable for type selection
requestDecodeIterable[the.`Unapp1[CookbookDetails]`.A, the.`Unapp1[CookbookDetails]`.F](request)

It's not really an improvement in this case, especially because I think the inferencer can just do it itself, but it might have other uses.

EDIT: Found it: it's called Unpack1 in shapeless.

Upvotes: 1

Related Questions