Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit resolution of dependent types in Scala

Consider the following piece of code:

trait Foo {
  type T
  def value: T
}

object Foo {
  def apply[A](v: A): Foo = new Foo {
    override type T = A
    override def value = v
  }
}

trait Decode[A] {
  def apply(x: A): String
}

object Decode {
  def apply[A](f: A => String): Decode[A] = new Decode[A] {
    override def apply(x: A) = f(x)
  }

  implicit val decodeStr: Decode[String] = Decode(identity)
}

class Sandbox {
  def decodeFoo(foo: Foo)(implicit decoder: Decode[foo.T]): String =
    decoder(foo.value)

  val foo = Foo("hello")
  println(decodeFoo(foo))
}

The above code should work fine and print hello but instead it fails to compile:

could not find implicit value for parameter decoder: Decode[Sandbox.this.foo.T]
[error]   println(decodeFoo(foo))

Even when I explicitly pass in the implicit param:

println(decodeFoo(foo = foo)(decoder = Decode.decodeStr))

I still get this error now:

type mismatch;
[error]  found   : Decode[String]
[error]  required: Decode[Sandbox.this.foo.T]
[error]   println(decodeFoo(foo = foo)(decoder = Decode.decodeStr))
[error]                                                 ^

Ofcourse, I can make Foo a Foo[T] and define decoders for it but that's not the point of this question - I want to understand why the above code fails to compile.

like image 542
pathikrit Avatar asked Nov 06 '17 16:11

pathikrit


People also ask

Does Scala have dependent types?

Scala has a notion of a type dependent on a value. This dependency is not expressed in the type signature but rather in the type placement.

What are implicit parameters in Scala?

Implicit parameters are the parameters that are passed to a function with implicit keyword in Scala, which means the values will be taken from the context in which they are called.

What is implicit object in Scala?

In Scala, objects and values are treated mostly the same. An implicit object can be thought of as a value which is found in the process of looking up an implicit of its type.

Where does Scala look for Implicits?

Scala will first look for implicit definitions and implicit parameters that can be accessed directly (without a prefix) at the point the method with the implicit parameter block is called. Then it looks for members marked implicit in all the companion objects associated with the implicit candidate type.


1 Answers

The problem exists here:

object Foo {
  def apply[A](v: A): Foo = new Foo {
    override type T = A
    override def value = v
  }
}

There, you've established that you will return a Foo but not, specifically, which Foo. Hence, that function only knows that it can return a Foo for any type T. You need an Aux pattern to recapture the type which is lost when establishing your new Foo (yes, yes...)

object Foo {
  type Aux[A] = Foo{ type T = A }

  def apply[A](v: A): Aux[A] = new Foo {
    type T = A
    def value = v
  }
}

which then says that for a given A produce the Foo which has it's T dependent type set to A.

like image 154
wheaties Avatar answered Oct 13 '22 15:10

wheaties