“не может экзистенциально абстрагировать по параметризованному типу …”

Я бездельничал с 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)

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

13
задан Tom Crockett 26 June 2010 в 02:38
поделиться

2 ответа

Я предполагаю, что это связано со следующими утверждениями в спецификации, § 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 спецификации) с вышеупомянутым ограничением. Однако я не знаю, почему существует это ограничение. Возникающая ошибка может быть найдена в классе 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}

11
ответ дан 2 December 2019 в 01:09
поделиться

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

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

0
ответ дан 2 December 2019 в 01:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: