Как использовать подстановочный знак для более высокого типа в Scala?

допустим, у меня есть эта черта

trait Ctx[C, V[_]]

Я не могу создать сигнатуру метода, которая принимает Ctx, параметр второго типа которого не указан (подстановочный знак). Е. Г. это:

def test(c: Ctx[_, _]) = ()

не компилируется ("error: _ takes no type parameters, expected: one"). Ни я могу сделать

def test(c: Ctx[_, _[_]]) = ()

("error: _ does not take type parameters"). Что я упускаю?

3 ответов


Я могу определить этот:

def test[V[X]](c:Ctx[_,V]) {}

и, похоже, работает нормально с выводом типа:

scala> trait Ctx[ C, V[ _ ]]
defined trait Ctx

scala> def test[V[X]](c:Ctx[_,V]) {}
test: [V[X]](c: Ctx[_, V])Unit

scala> class P extends Ctx[Int, List]
defined class P

scala> new P
res0: P = P@1f49969

scala> test(res0)

редактировать: я подозреваю, что заменить Ctx использовать абстрактный тип, но это то, что мне удалось сделать:

trait Ctx[C] { type V[X] }
class CtxOption[C] extends Ctx[C] { type V[X] = Option[X] }
class CtxList[C] extends Ctx[C] { type V[X] = List[X] }

def test(ctx:Ctx[_]) { println(ctx) }

val ctxOptInt = new CtxOption[Int]
val ctxListStr = new CtxList[String]

test(ctxOptInt)
test(ctxListStr)

val list = collection.mutable.ListBuffer[Ctx[_]]()
list += ctxOptInt
list += ctxListStr
list

использование абстрактного типа для V избавляет вас от сложной (или невозможной) задачи вычисления синтаксиса параметра типа для конструктора подстановочного типа. Дополнительно, как показано в the ListBuffer пример вы можете обрабатывать объекты, где V является конструктором другого типа (опции и список в моем примере). Первое решение, которое я предложил, не позволит вам этого сделать.

Edit 2: как насчет?

trait AbstractCtx[C] { type W[X] }
trait Ctx[C,V[_]] extends AbstractCtx[C] { type W[X] = V[X] }
def test(ctx:AbstractCtx[_]) { println(ctx) }

вам нужно передать конструктор типа для второго аргумента Ctx. Scala не в состоянии сделать правильный вывод, если вы просто пройти _. Также невозможно определить конструктор типа с подстановочными знаками (т. е. _[_]] на лету. Обратите внимание, что в первом примере _ в сообщении об ошибке ссылается на тип, переданный в качестве второго аргумента Ctx в целом. Во втором примере, однако _ относится к первому типу wildcard в _[_]. Индикатор местоположения в сообщениях об ошибках:

<console>:6: error: _ does not take type parameters
       def test( c: Ctx[ _, _[ _ ]]) {}
                            ^

следующие работы, так как здесь V является конструктором типа правильного типа, ожидаемого Ctx.

def test[V[_]]( c: Ctx[ _, V]) {}

все объяснено здесь. Сосредоточьтесь на разделе" Общие подводные камни " внизу.