I am trying to "unwrap" a type variable from a generic type (without using reflection). E.g. in the case of an Option, the goal would be that the following (or similar) code compiles:
implicitly[OptionUnwrapper[Option[Int]] =:= Int]
I managed to come up with the following unwrapper:
trait OptionUnwrapper[T] {
type Unwrap[_ <: Option[T]] = T
}
which can be used to as follows:
implicitly[OptionUnwrapper[Int]#Unwrap[Option[Int]] =:= Int]
The problem with this solutions is, that I have to declare the type (in my case Int) of interest, before it can be returned. Is there a way to leaf out this parameter like for instance in generic functions like:
def foo[T](x: Option[T]) = x.isDefined
foo[Int](Some(1)) // function call with unnecessary type parameter,
foo(Some(1)) // since compiler infers Int automatically
UPDATE 1 - Use Case:
In my actual use case, I want to receive a "tuple type" from a case class. i.e. lets say I have a case class
case class Person(name: (String, String), age: Int, hobbies: List[String])
I want something that yields the type of the unapplied Person. i.e.
type T = Tupled[Person] // T =:= Tuple3[Tuple2[String, String], Int, List[String]]
I tried to get to this point by using the type of the Person.unapply function, which would be
Function1[Person, Option[Tuple3[...]]]
From this point, the plan would be to "unwrap" the Function1[_, Option[X]]
to X
(Note that I'm addressing the actual use case instead of the original "Unwrap type variables" question)
As I said in a comment, If you are willing to use a macro, I have already provided a macro that fits the bill:
How to do generic tuple -> case class conversion in Scala?
You can then just do:
val PersonFactory = CaseClassFactory[Person]
type PersonTuple = PersonFactory.Tuple
But given that you are also ready to put up with some boilerplate for each case class, you can also go for a macro-less solution:
implicit class TupleTypeProvider[O,T](unapply: O => Option[T]) { type Tuple = T }
def tupleTypeProvider[O,T](implicit p: TupleTypeProvider[O,T]) = p
// Usage
case class Person(name: (String, String), age: Int, hobbies: List[String])
val personTupleInfo = tupleTypeProvider(Person.unapply _)
type PersonTuple = personTupleInfo.Tuple
// Let's check:
implicitly[PersonTuple =:= Tuple3[Tuple2[String, String], Int, List[String]]]
Or similarly:
implicit class TupleTypeProvider[O,T](tupled: T => O) { type Tuple = T }
def tupleTypeProvider[O,T](implicit p: TupleTypeProvider[O,T]) = p
// Usage
case class Person(name: (String, String), age: Int, hobbies: List[String])
val personTupleInfo = tupleTypeProvider((Person.apply _).tupled)
type PersonTuple = personTupleInfo.Tuple
// Let's check:
implicitly[PersonTuple =:= Tuple3[Tuple2[String, String], Int, List[String]]]