Pregunta

Me estaba metiendo con Scala 2,8 por diversión y tratando de definir un proxeneta que añade un "como" método para escribir constructores, lo que permite convertir de un funtor a otro (por favor, pasar por alto el hecho de que no estoy necesariamente se trata de funtores aquí). Así, por ejemplo, se puede utilizar de esta manera:

val array:Array[T]
val list:List[T] = array.as[List]

Así que aquí es lo que he intentado hacer:

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
    }
}

sin embargo la definición de naturalTransformations se encuentra en posición con el error "no puede existencialmente abstracto sobre tipo parametrizado G [T]" . Para solucionar este problema, puedo reescribir naturalTransformations junto con un Transformable clase adicional de esta manera:

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)

y parece trabajo. Pero parece que mi primer intento debería haber sido equivalentes, así que estoy curioso por qué ha fallado y lo que significa el mensaje de error.

¿Fue útil?

Solución

Mi impresión sería que esto se debe a que, debido a las siguientes declaraciones en la especificación, § 6.11, bloques:

  

Un tipo definido localmente definición de tipo t = T está obligado por la cláusula existencial   escriba t>: T <: T. Es un error si t lleva parámetros de tipo.

Y una expresión creación de la instancia estructural se evalúa a un bloque, por lo que


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

es una abreviatura para


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

por lo que se evalúa como una expresión de bloque (de acuerdo con § 6.10 de la especificación), con la restricción mencionada. ¿Por qué existe esta restricción es que no sé, sin embargo. El error que se produce se puede encontrar en la clase Typers a esta ubicación, lo que parece confirmar que esta restricción es la causa del error que se ve. Como se ha mencionado, la codificación de la función en una clase elimina la restricción expresión bloque:


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}

Otros consejos

Para mí esto suena como una simplicidad contra la caja generalidad: podría haber una nueva variable de tipo generado cada vez que se crea un bloque de captura de algún tipo constructor de instancia con el tipo existencial, pero eso haría que el diagnóstico de errores más difíciles de entender.

Tenga en cuenta también que el tener una clase convierte la llamada en una INVOKEVIRTUAL rápido, en vez de invocar como () método de reflexión.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top