SOLVED: Type parameter not binding with function's parameter type. How to force?


I have the following trait:

  sealed trait Val[V] {
    val v: V

I create instances of these implicitly using this definition:

  implicit def pack[A](s:A) : Val[A] = new Val[A] {
    println(s"Packing $s")
    override val v: A = s

for example I can do the following:

    val r5: Val[String] = "100"
    println(s"r5: Val(${r5.v}) : ${r5.v.getClass}")
    val r6: Val[Double] = 200.0
    println(s"r6: Val(${r6.v}) : ${r6.v.getClass}")
    val r7: Val[Array[Double]] = Array(300.0, 301, 302)
    println(s"r7: Val(${r7.v.mkString(",")}) : ${r7.v.getClass}")

I can store these values so:

    val rs = Map("x" -> r5, "y" -> r6, "z" -> r7)
    println(s"rs = $rs")
    val s5 = rs("x")
    val s6 = rs("y")
    val s7 = rs("z")

I now want to unpack the value using these definitions:

  def test[A,B](av: Val[A], f: A => B)(implicit a: Val[A] => Either[String,A]): Either[String,B] = {
    a(av).flatMap( e => Right(f(e)) )

  implicit def unpack[T](t:Val[_]): Either[String,T] = {
    try {
      val v = t.v.asInstanceOf[T]
    } catch {
      // When used via implicits should never reach this
      case e:Exception => Left(e.getMessage)

If I use the instances that have their types known at compile time, I can do this:

    val u0 = test(r5, (e:String) => e.toInt)
    val u1 = test(r6, (e:Double) => e)
    val u2 = test(r7, (e:Array[Double]) => e)

However, If I do the following:

    val v0 = test(s5, (e:String) => e.toInt)
    val v1 = test(s6, (e:Double) => e)
    val v2 = test(s7, (e:Array[Double]) => e)

I get compilation errors: For example:

[error] AutoVal.scala:149: type mismatch;
[error]  found   : String => Int
[error]  required: _1 => Int where type _1 >: Array[Double] with Double with String
[error]     val v0 = test(s5, (e:String) => e.toInt)
[error]                                  ^

Which is not what I expected. I assumed that the type of the first parameter of the
anonymous function in test is fully defined and it should there be enough to set
the type T in unpack. However the String in the error message above does not
impose the type of _1.

So my questions are: why is this not so and is there a way for one “force” this?


Perhaps the following is useful. Modify your trait to

 sealed trait Val[V] {
    val v: V
    type MyType = V

and then use this to cast.


Thanks for the feedback Siddhartha. Unfortunately I had tried that route already but could not get it to work.
The problem is that to “store” that information, the compiler must retain the type information. Once the Val is
placed in a container F[Val[_]] however, that information is lost to the compiler.

However, I found the problem. All I need to do is not use the “unknown” type in Val of the test function.
Fact is, I am only using the anonymous function to establish the type and try and cast it during run-time
So, the test function should be:

  def test[A,B](av: Val[_], f: A => B)(implicit a: Val[_] => Either[String,A]): Either[String,B] = {
    a(av).flatMap( e => Right(f(e)) )