"не может экзистенциально абстрагироваться от параметризованного типа ..." - PullRequest
13 голосов
/ 26 июня 2010

Я развлекался со Scala 2.8 для забавы и пытался определить pimp , который добавляет метод "as" к типу конструкторов, позволяя конвертировать из одного функтора в другой (пожалуйста, пропустите тот факт, что яне обязательно иметь дело с функторами здесь).Например, вы можете использовать его следующим образом:

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)

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

Ответы [ 2 ]

11 голосов
/ 26 июня 2010

Думаю, это связано с тем, что из-за следующих операторов в блоках спецификации, § 6.11:

Локально определенный тип определения типа t = T связан типом экзистенциального предложенияt>: T <: T.Это ошибка, если t содержит параметры типа. </p>

И выражение создания структурного экземпляра оценивается как блок, поэтому


new {def greet{println("hello")}}

является сокращением для


{ class anon$X extends AnyRef{ def greet = println("hello") }; new anon$X }

, поэтому он оценивается как выражение блока (согласно § 6.10 спецификации) с вышеупомянутым ограничением.Почему это ограничение, я не знаю, однако.Возникшая ошибка может быть найдена в классе Typers по адресу в этом месте , что, по-видимому, подтверждает, что это ограничение является причиной ошибки, которую вы видите.Как вы упомянули, кодирование функции в классе снимает ограничение выражения блока:


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}

0 голосов
/ 26 июня 2010

Для меня это звучит как простота на фоне общности: может быть новая переменная типа, генерируемая каждый раз, когда создается блок, захватывая некоторый конструктор типа, созданный с экзистенциальным типом, но это усложнит понимание диагностики ошибок.

Также обратите внимание, что наличие класса превращает вызов в быстрый INVOKEVIRTUAL, а не вызывает как () метод с помощью отражения.

...