Шаблон класса типа в Scala не учитывает наследование?

В некоторых случаях я разрабатываю API с использованием классов типов, однако я столкнулся с проблемой неявного разрешения. Как показано ниже, если существует неявный объект для типа A, но объект типа B extends A передается методу, то неявный объект не может быть найден. Есть ли способ заставить эту работу работать или вызывающие должны помещать неявные объекты в область видимости для каждого подкласса?

Вот пример:

class A
class B extends A

class T[+X]

object T {
  implicit object TA extends T[A]
}

def call[X:T](x:X) = println(x)

// compiles
call(new A)
// doesn't compile
call(new B)

var a = new A
// compiles
call(a)

a = new B
// compiles
call(a)

val b = new B
// doesn't compile
call(b)

Это не может быть скомпилировано со следующим выводом:

/private/tmp/tc.scala:16: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(new B)
    ^
/private/tmp/tc.scala:28: error: could not find implicit value for evidence parameter of type this.T[this.B]
call(b)

person Jesse Eichar    schedule 06.10.2010    source источник
comment
Я также попытался изменить определение вызова на: def call [X, X2 ‹: X] (x: X2) (implicit x2: T [X]) = println (x) И это не помогло.   -  person Jesse Eichar    schedule 06.10.2010


Ответы (3)


Вызов call(new B) означает call[B](new B)(tB) такой, что tb имеет тип T [B] или его подкласс. (Метод, который ожидает аргумент типа T, может ожидать только T или подкласс T, например, def foo(s: String) не может быть вызван с аргументом типа Any). T [A] не является подтипом T [B]

Чтобы исправить это, вы можете изменить T на определение T[-X]. Это означает, что компилятор будет рассматривать T [A] как подтип T [B].

person IttayD    schedule 06.10.2010
comment
Проблема в том, что даже если вы также определяете implicit object TB extends T[B], implicitly[T[B]] == T.TA. lampvn.epfl.ch/trac/scala/ticket/2509 - person retronym; 07.10.2010
comment
звучит разумно, потому что TA в этом случае более специфичен, чем TB, а TA - это TB, поэтому его следует использовать там, где T [B]. если вы хотите, чтобы неявное совпадение точно соответствовало типу, определите T как T [X] - person IttayD; 07.10.2010

Следующее работает нормально:

scala> def call[X](x: X)(implicit evidence: T[X]<:<T[X])  = println(x)
call: [X](x: X)(implicit evidence: <:<[T[X],T[X]])Unit

scala> call(new A)
line0$object$$iw$$iw$A@1d869b2

scala> call(new B)
line2$object$$iw$$iw$B@b3a5d1

scala> val b = new B
b: B = B@30e4a7

scala> call(b)
line2$object$$iw$$iw$B@30e4a7

В вашем случае компиляция не удалась, потому что def call[X:T](x:X) = println(x) рассматривается как call: [X](x: X)(implicit evidence$1: T[X])Unit. Чтобы передать подтип, вы можете использовать ограничения обобщенного типа.

person Vasil Remeniuk    schedule 06.10.2010
comment
Есть ли способ получить доказательства на 1 доллар? Например, предположим, что T - это функция, а x - параметр. Я не могу назвать доказательствами (х) - person Jesse Eichar; 06.10.2010
comment
Почему ты не можешь? Вы можете вызвать его по имени evidence$1, как и любой другой [неявный] параметр. - person Vasil Remeniuk; 06.10.2010
comment
Если у вас есть несколько параметров типа в методе, будет доказательство $ 1, доказательство $ 2 и т. Д .: [X,Z](x: X)(implicit evidence$1: T[X],implicit evidence$2: T[Z])Unit - person Vasil Remeniuk; 06.10.2010
comment
Мой вопрос не совсем соответствовал моим потребностям. Мне понравился этот совет, но мои настоящие потребности оказались следующими: ‹code› черта T [X] расширяет Function1 [X, Boolean] ‹/code›. и вызов: ‹code› def call [X] (x: X) (неявный x2: T [X]) = x2 (x) ‹/code›. Оказалось, что использование T [-X] сработало для меня. Хотя здорово узнать о ‹:‹. - person Jesse Eichar; 06.10.2010
comment
@ jesse-eichar Если T [-X] сработал для вас, почему бы не принять предоставленный мной ответ? - person IttayD; 07.10.2010

Попробуй это:

object T {
  implicit def TA[X <: A] = new T[X]
}

import T._

или просто:

implicit def TA[X <: A] = new T[X]
person Tom Crockett    schedule 06.10.2010