2

Is it possible to access the type constructor parameter of a higher-kinded type in a context bound? I am looking to define a trait that takes a higher-kinded type, and has a method that returns an instance of the constructor parameter.

case class A[TContents](c: TContents) {
  def foo = c
}

case class B[TContents](c: TContents) {
  def foo = c
}

trait Fooable[TClass[_ <: TContents], TContents] {
  def foo(obj: TClass[TContents]): TContents
}

case class AFooable[TContents] extends Fooable[A, TContents] {
  def foo(obj: A[TContents]) = obj.foo
}

case class BFooable[TContents] extends Fooable[B, TContents] {
  def foo(obj: B[TContents]) = obj.foo
}

class test {
  def getFoo[TType[_] : Fooable, TContents](obj: TType[TContents]): TContents = 
    implicitly[Fooable[TType, TContents]].foo(obj)

  implicit def aFooable = AFooable

  val a = A(1)
  val foo = getFoo(a)
}

This fails with compiler error complaining that context bounds cannot have two type parameters, but I cannot find another way to access the type constructor parameter?

kiritsuku
  • 52,967
  • 18
  • 114
  • 136
Woodz
  • 1,029
  • 10
  • 24

1 Answers1

3

You have two options—either use the type lambda trick to partially apply Fooable (ugh):

def getFoo[TType[_]: ({type L[A[_]] = Fooable[A, TContents]})#L, TContents](
  obj: TType[TContents]
): TContents = implicitly[Fooable[TType, TContents]].foo(obj)

Or desugar the context bound (much nicer, in my opinion):

def getFoo[TType[_], TContents](obj: TType[TContents])(
  implicit ev: Fooable[TType, TContents]
): TContents = ev.foo(obj)

Note that in either case you'll need to give your aFooable a type parameter:

implicit def aFooable[A] = AFooable[A]

And I'd strongly advise obeying the warnings about parameter list-less case classes.

Community
  • 1
  • 1
Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Thanks for the suggestions. As I suspected, the syntactic sugar for context bounds cannot handle multiple type parameters. I wonder if this is oversight or a limitation of the language? – Woodz Dec 06 '12 at 14:24
  • Lots of folks want partially applied types for different reasons (your case being one of them); see for example [this compiler plugin](https://github.com/non/kind-projector). To answer your question, though, I'd guess that it was a conscious decision to avoid yet more Scala syntax. – Travis Brown Dec 06 '12 at 14:34