Question

Je suis de déconner avec Scala 2.8 pour le plaisir et essayer de définir un proxénète qui ajoute un « comme » méthode pour saisir les constructeurs, ce qui permet de convertir d'un foncteur à un autre (s'il vous plaît négliger le fait que je traite pas nécessairement avec foncteurs ici). Ainsi, par exemple, vous pouvez l'utiliser comme ceci:

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

Alors, voici ce que j'ai essayé de le faire:

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

Toutefois, la définition de naturalTransformations est marqué avec l'erreur "ne peut pas existentiellement abstraite sur le type paramétrées G [T]" . Pour résoudre ce problème, je peux réécrire naturalTransformations avec une Transformable de classe supplémentaire comme ceci:

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)

et il semble fonctionner. Mais il semble que ma première tentative aurait dû être équivalent, donc je suis curieux de savoir pourquoi il a échoué et ce que les moyens de message d'erreur.

Était-ce utile?

La solution

Mon intuition serait que cela est dû en raison des énoncés suivants dans la spécification, § 6.11, blocs:

  

Un type de définition de type défini localement t = T est lié par la clause existentielle   type T>: T <: T. Il y a une erreur si t porte paramètres de type.

Et une expression de la création d'instance de structure est évaluée à un bloc, donc


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

est un raccourci pour


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

il évalue une expression de bloc (selon § 6.10 de la spécification), avec la restriction précitée. Pourquoi cette restriction est là, je ne sais pas, cependant. L'erreur qui est jetée se trouve dans la classe typers cet endroit , ce qui semble confirmer que cette restriction est la cause de l'erreur que vous voyez. Comme vous l'avez mentionné, codant pour la fonction dans une classe supprime la restriction de l'expression du bloc:


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}

Autres conseils

Pour moi, cela sonne comme une simple contre cas de généralité: il pourrait y avoir une nouvelle variable de type généré chaque fois qu'un bloc est créé capturer un certain constructeur de type instancié avec le type existentiel, mais qui rendrait les diagnostics d'erreur plus difficile à comprendre.

Notez également que d'avoir une classe transforme l'appel en invokevirtual rapide, plutôt que d'invoquer () méthode par réflexion.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top