Ответ 1
Здесь работает подсветка -Xprint:typer
. Проблема с test2
что существует экзистенциальный тип, который появляется в двух отдельных местах: оба
write.value
и write.writer
имеют экзистенциальный тип, но, в решающей степени,
компилятор не знает, что они имеют одинаковые экзистенциальные
количественная переменная типа. Даже если вы обращаетесь к ним с одного и того же объекта,
компилятор забывает, что они пришли из того же места.
Когда test1
полностью набрано, вы увидите:
def test1(set: Set[Write[_]], cache: Cache) =
set.foreach(((x0$1: Write[_]) => x0$1 match {
case (value: _$1, writer: Writer[_$1])Write[_$1]((value @ _), (writer @ _)) =>
cache.store[_$1](value, writer)
}));
Переменная типа _$1
совпадает со значениями. Соответствие переменной типа _$1
связывает ее в
область case
, поэтому она больше не существует, и Scala может сказать
что value
и writer
имеют один и тот же параметр типа.
Решение для test2
состоит в том, чтобы не использовать экзистенции:
def test2[A]( set: Set[ Write[ A ]], cache: Cache ) {
set.foreach { write =>
cache.store( write.value, write.writer )
}
}
или привязать переменную типа с совпадением:
def test2( set: Set[ Write[ _ ]], cache: Cache ) {
set.foreach { case write: Write[a] =>
cache.store( write.value, write.writer )
}
}
изменить
Позвольте мне попытаться ответить на новые вопросы, которые вы подняли.
Причина test3
не работает, это когда вы пишете:
set.foreach(процесс)
process
, который является полиморфным, должен быть мономорфным по двум причинам (о котором я знаю):
-
Функции в Scala не могут быть полиморфными; могут быть только методы.
process
как определено как метод; когда используется как функция первого класса, это функция. -
То, как компилятор делает вывод типа, в основном, принимает полиморфные значения и объединяет их вместе, чтобы сделать их менее полиморфными. Передача фактического полиморфного значения в качестве аргумента метода потребует более ранних типов.
Причина, по которой test4
работает, заключается в том, что функция literal:
set.foreach( w => process( w ))
на самом деле не является полиморфной функцией! В качестве аргумента он берет на себя обязательный критерий; но не полиморфного типа. Затем он вызывает метод (а не функцию) process
и сопоставляет переменную типа экзистенциального типа с параметром process
. Довольно дикая, а?? // " >
Вы также можете написать:
set.foreach( process(_) )
который, создавая анонимную функцию, означает одно и то же.
Другим маршрутом, который вы можете найти или не найти подходящим, было бы отбросить экзистенциальные типы и члены типа использования:
trait Writable {
type A
val value: A
val writer: Writer[A]
}
case class Write[T]( value: T, writer: Writer[ T ]) extends Writable {
type A = T
}
def test2( set: Set[Writable], cache: Cache ) {
set.foreach { write =>
cache.store( write.value, write.writer )
}
}
Здесь Scala может видеть, что write.value
и write.writer
имеют одинаковые
type, потому что они имеют одинаковый тип зависимого от пути.