How to define a context bound with a higher kinded Type (Type Constructor)

236 views Asked by At

I have tried the following

def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}

but does not work ? Any idea what's the issue ?

EDIT

This of course works

def test[T](value1: Option[T], value2: Option[T]) (implicit ev: Ordering[Option[T]]) = {
  ev.compare(value1, value2)
}
2

There are 2 answers

1
Jasper-M On BEST ANSWER

If you really insist on using a context bound you can write a type lambda:

def test[T: ({type L[x] = Ordering[Option[x]]})#L](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}

Or with the kind-projector plugin you should be able to make this a bit cleaner:

def test[T: Lambda[x => Ordering[Option[x]]]](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}
0
Dmytro Mitin On

When you write def test[Option[T]: Ordering]... the Option doesn't refer to scala.Option, it's a new type parameter (you can denote it Option or F whatever). So

def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}

is actually

def test[F[_]: Ordering](value1: F[T], value2: F[T]) = {
  val e = implicitly(Ordering[F[T]].compare(value1, value2))
}

aka

def test[F[_]](value1: F[T], value2: F[T])(implicit ev: Ordering[F]) = {
  val e = implicitly(Ordering[F[T]].compare(value1, value2))
}

This does't compile because T is not defined and Ordering[F] doesn't make sense. What would compile is

def test[F[_], T](value1: F[T], value2: F[T])(implicit ev: Ordering[F[T]]) = {
  val e = implicitly(Ordering[F[T]].compare(value1, value2))
}

I would recomment to switch on scalacOptions += "-Xlint:type-parameter-shadow".