«Не может экзистенциально аннотация по сравнению с параметризованным типом ...»
Вопрос
Я возился со Scala 2.8 для удовольствия и пытается определить суперизм который добавляет метод «как», чтобы ввести конструкторы, позволяющие преобразовать от одного функтора в другую (пропустить тот факт, что я не обязательно имел дело с функторами здесь). Так, например, вы могли бы использовать это так:
val array:Array[T]
val list:List[T] = array.as[List]
Так вот то, что я пытался сделать:
object Test {
abstract class NatTrans[F[_], G[_]] {
def convert[T](f:F[T]):G[T]
}
implicit def array2List:NatTrans[Array, List] = new NatTrans[Array, List] {
def convert[T](a:Array[T]) = a.toList
}
// this next part gets flagged with an error
implicit def naturalTransformations[T, F[_]](f:F[T]) = new {
def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
}
}
Однако определение naturalTransformations
помечен с ошибкой «Не может экзистенциально аннотация по параметризованному типу G [T]». Отказ Чтобы исправить это, я могу переписать naturalTransformations
вместе с дополнительным классом Transformable
вот так:
class Transformable[T, F[_]](f:F[T]) {
def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
}
implicit def naturalTransformations[T, F[_]](f:F[T]) = new Transformable[T, F](f)
И это похоже на работу. Но кажется, что моя первая попытка должна была быть эквивалентной, поэтому мне любопытно, почему он не удался и что означает сообщение об ошибке.
Решение
Моя догадка будет то, что это потому, что из-за следующих утверждений в спецификации § 6.11, блоки:
Локально определенный тип определения типа T = T связан с помощью экзистенциального типа предложения T>: T <: T. Это ошибка, если T несет параметры типа.
И выражение создания структурных экземпляров оценивается в блок, так
new {def greet{println("hello")}}
это сокращение для
{ class anon$X extends AnyRef{ def greet = println("hello") }; new anon$X }
Таким образом, он оценивает экспрессию блока (согласно § 6.10 спецификации), с вышеупомянутым ограничением. Почему это ограничение там, я не знаю, однако. Ошибка, которая бросается, можно найти в классе типов на Это местоположение, который, похоже, подтверждает, что это ограничение является причиной ошибки, которую вы видите. Как вы упоминали, кодирование функции в классе удаляет ограничение выражения блока:
scala> class N[M[_]]
defined class N
scala> class Q { def as[M[_]](n:N[M]) = null}
defined class Q
scala> new { def as[M[_]](n:N[M]) = null}
:7: error: can't existentially abstract over parameterized type M
new { def as[M[_]](n:N[M]) = null}
Другие советы
Для меня это звучит как простота против общего случая.
Также обратите внимание, что наличие класса превращает звонок в быстрое вызование, а не вызывающую так как() метод отражением.