2017-01-05 1 views
1

J'essaie de porter des parties d'une bibliothèque Haskell pour la programmation de type de données générique vers Scala. Voici le problème que j'ai rencontré:Scala: paramètres de type multiple pour la classe implicite

J'ai défini un trait, Generic, avec un paramètre de type conteneur:

trait Generic[G[_]] { 
    // Some function declarations go here 
} 

Maintenant, j'ai une classe abstraite, Collect, avec trois paramètres de type, et une déclaration de fonction (il signifie un type que peut recueillir tous les subvalues ​​de type B dans un récipient de type F[_] d'une certaine structure de type A):

abstract class Collect[F[_],B,A] { 
    def collect_ : A => F[B] 
} 

pour faire étendre générique, les deux paramètres de type premier F[_] et B sont donnés, et A est cari (cet effet est simulé à l'aide lambdas de type):

class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] { 
    // Function definitions go here 
} 

Le problème est que j'ai besoin de la dernière définition de classe pour être implicite , parce que plus tard dans mon code, je dois être capable d'écrire des fonctions comme

class GUnit[G[_]](implicit gg: Generic[G]) { 
    // Some definitions 
} 

Quand je PREPEND implicit à simplement la définition de la classe, je reçois l'erreur en disant implicit classes must accept exactly one primary constructor parameter. Quelqu'un at-il rencontré un problème similaire? Existe-t-il un moyen connu de contourner ce problème? Je ne vois pas actuellement comment je pourrais refactoriser mon code tout en gardant la même fonctionnalité, donc tout conseil est le bienvenu. Merci d'avance!

Répondre

4

Les classes implicites ne fonctionnent pas de cette façon. Ils sont un raccourci pour conversions implicites. Par exemple implicit class Foo(i: Int) est égal à class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i). Donc, cela ne fonctionne qu'avec les classes qui ont exactement un paramètre dans leur constructeur. Cela n'aurait aucun sens pour la plupart des classes de paramètres (types). Le titre de votre question semble également suggérer que vous pensez que l'erreur de compilation parle de paramètres de type du constructeur de type, mais j'espère que le paragraphe ci-dessus indique également qu'il est en fait parler de valeur paramètres de la valeur constructeur.

Pour ce que vous essayez de faire (je pense), vous devrez fournir une instance implicite de CollectC. Je suggère de le mettre dans l'objet compagnon de Collect. Mais vous pouvez choisir un alternative solution si cela correspond mieux à vos besoins.

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait Generic[G[_]] { 
    // Some function declarations go here 
} 

abstract class Collect[F[_],B,A] { 
    def collect_ : A => F[B] 
} 

object Collect { 
    implicit def mkCollectC[F[_],B]: CollectC[F,B] = new CollectC[F,B] 
} 

class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] { 
    // Function definitions go here 
} 

// Exiting paste mode, now interpreting. 

warning: there were four feature warnings; for details, enable `:setting -feature' or `:replay -feature' 
defined trait Generic 
defined class Collect 
defined object Collect 
defined class CollectC 

scala> implicitly[Generic[({type C[X] = Collect[List,Int,X]})#C]] 
res0: Generic[[X]Collect[[+A]List[A],Int,X]] = [email protected] 
+0

Cela a été très utile, merci! – Rrr