Доступ к параметру конструктора типа границ контекста с более высокими родственными типами

Можно ли получить доступ к параметру конструктора типа более высокого типа в привязке к контексту? Я хочу определить трейт, который принимает тип более высокого типа и имеет метод, который возвращает экземпляр параметра конструктора.

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)
}

Это терпит неудачу с ошибкой компилятора, жалующейся на то, что границы контекста не могут иметь два параметра типа, но я не могу найти другой способ получить доступ к параметру конструктора типа?


person Woodz    schedule 06.12.2012    source источник


Ответы (1)


У вас есть два варианта: либо использовать трюк лямбда-типа, чтобы частично применить Fooable (тьфу):

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

Или desugar связанный с контекстом (гораздо лучше, на мой взгляд):

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

Обратите внимание, что в любом случае вам нужно указать aFooable параметр типа:

implicit def aFooable[A] = AFooable[A]

И я настоятельно рекомендую следовать предупреждениям о классах без списка параметров.

person Travis Brown    schedule 06.12.2012
comment
Спасибо за предложения. Как я и подозревал, синтаксический сахар для границ контекста не может обрабатывать несколько параметров типа. Интересно, это недосмотр или ограничение языка? - person Woodz; 06.12.2012
comment
Многим людям нужны частично применяемые типы по разным причинам (ваш случай — один из них); см., например, этот подключаемый модуль компилятора. Однако, чтобы ответить на ваш вопрос, я предполагаю, что это было сознательное решение избежать еще большего количества синтаксиса Scala. - person Travis Brown; 06.12.2012