Un ami m'a posé une apparence anodins Scala question de la langue, la semaine dernière que je n'ai pas une bonne réponse à la question de savoir si il existe un moyen facile de déclarer une collection de choses appartenant à une communauté de typeclass. Bien sûr, il n'y a pas de première classe de la notion de "typeclass" en Scala, de sorte que nous devons penser en termes de traits de personnalité et le contexte de limite (c'est à dire implicites).
Concrètement, compte tenu de certains traits T[_]
représentant un typeclass, et les types d' A
, B
et C
, correspondant implicites dans le champ d'application T[A]
, T[B]
et T[C]
, nous voulons déclarer quelque chose comme un List[T[a] forAll { type a }]
, dans laquelle nous pouvons jeter les instances de l' A
, B
et C
avec l'impunité. Bien sûr, cela n'existe pas dans la Scala; une question l'année dernière traite de cette question plus en profondeur.
Le prolongement naturel de la question est "comment Haskell faire?" Eh bien, GHC, en particulier, a un système de type extension appelée impredicative polymorphisme, décrit dans le "Boxy"Types de papier. En bref, compte tenu d'une typeclass T
on peut légalement construire une liste [forall a. T a => a]
. Donné une déclaration de ce formulaire, le compilateur ne dictionnaire de passage de magie qui nous permet de conserver la typeclass instances correspondant aux types de chaque valeur de la liste au moment de l'exécution.
Chose est, le "dictionnaire de passage de la magie" sonne un peu comme "vtables." Dans un langage orienté objet comme la Scala, le sous-typage est beaucoup plus simple, le mécanisme naturel de la "Boxy" Types d'approche. Si notre A
, B
et C
tous étendre trait T
, alors on peut simplement déclarer List[T]
et d'être heureux. De même, à mesure que les Kilomètres de notes dans un commentaire ci-dessous, si ils sont tous d'étendre les traits T1
, T2
et T3
alors je peux utiliser List[T1 with T2 with T3]
comme un équivalent de la impredicative Haskell [forall a. (T1 a, T2 a, T3 a) => a]
.
Toutefois, le principal, bien connu inconvénient de sous-typage par rapport à typeclasses est le couplage: mon A
, B
et C
types de ont leur T
comportement cuit. Imaginons que c'est l'un des principaux dealbreaker, et je ne peux pas utiliser de sous-typage. De sorte que le milieu de terrain de la Scala est proxénètes^H^H^H^H^Himplicit conversions: compte tenu de certains A => T
, B => T
et C => T
dans implicite portée, je peux à nouveau très heureux de remplir un List[T]
mon A
, B
et C
valeurs...
... Jusqu'à ce que nous voulons List[T1 with T2 with T3]
. À ce point, même si nous avons des conversions implicites A => T1
, A => T2
et A => T3
, on ne peut pas mettre un A
dans la liste. Nous avons pu restructurer nos conversions implicites à fournissons A => T1 with T2 with T3
, mais je n'ai jamais vu quelqu'un le faire avant, et il semble être encore une autre forme de couplage.
Ok, donc ma question, enfin, est, je suppose, une combinaison d'un couple de questions qui ont été précédemment demandé: "pourquoi éviter de sous-typage?" et "les avantages de sous-typage sur typeclasses" ... est-il une théorie unificatrice qui dit impredicative polymorphisme et le sous-type de polymorphisme sont une seule et même chose? Sont conversions implicites en quelque sorte le secret de l'amour-l'enfant des deux? Et quelqu'un peut-il articuler un bon modèle pour l'expression de plusieurs limites (comme dans le dernier exemple ci-dessus) à la Scala?