2009-11-12 4 views
26

Faisant suite à une autre question que je posais, Scala 2.8 breakout, je voulais comprendre un peu plus sur la méthode Scala TraversableLike[A].map dont la signature est la suivante:Scala 2.8 CanBuildFrom

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That 

avis quelques choses sur cette méthode :

  • Il prend une fonction en transformant chaque A dans le cheminement en B. Il renvoie That et prend un argument implicite de type CanBuildFrom[Repr, B, That].

Je peux appeler cela comme suit:

> val s: Set[Int] = List("Paris", "London").map(_.length) 
s: Set[Int] Set(5,6) 

Qu'est-ce Je ne peux pas tout à fait saisissais est comment le fait que That est lié-B (qui est, il est une collection de B) est en train d'être appliqué par le compilateur. Les paramètres de type semblent être indépendant de la signature ci-dessus et de la signature du trait CanBuildFrom lui-même:

trait CanBuildFrom[-From, -Elem, +To] 

Comment le compilateur Scala assurant que That ne peut pas être forcé en quelque chose qui n'a pas de sens?

> val s: Set[String] = List("Paris", "London").map(_.length) //will not compile 

Comment le compilateur décider quels objets CanBuildFrom implicites sont dans la portée de l'appel?

+0

Voici le poste avec une explication très agréable http://blog.bruchez.name/2012/08/getting-to-know-canbuildfrom-without-phd.html –

+0

Pour mémoire, une telle utilisation a un nom conceptuel: polymorphisme du type de retour. – lcn

Répondre

29

Notez que le second argument à map est un argument implicite. Il doit être une portée implicite avec les types appropriés, ou, sinon, devez passer un tel argument.

Dans votre exemple, That doit être Set[String], B doit être Int et Repr doit être List[String]. Par conséquent, pour que compiler vous avez besoin de l'objet implicite dans la portée:

implicit object X: CanBuildFrom[List[String], Int, Set[String]] 

Il n'y a rien de tel. De plus, breakOut ne peut pas le fournir, car il a lui-même besoin d'un CanBuildFrom implicite, dont le premier type peut être n'importe quelle classe (un descendant à contre-sens de Nothing), mais autrement restreint par les autres types.

Jetez un oeil, par exemple, sur l'usine CanBuildFrom de l'objet compagnon de List:

implicit def canBuildFrom [A] : CanBuildFrom[List, A, List[A]] 

Parce qu'il lie les deuxième et troisième paramètres par A, l'implicite en question ne fonctionnera pas. Alors, comment sait-on où chercher, en ce qui concerne ces implicites? Tout d'abord, Scala importe peu de choses dans tous les domaines.En ce moment, je peux rappeler les importations suivantes:

import scala.package._ // Package object 
import scala.Predef._ // Object 
// import scala.LowPriorityImplicits, class inherited by Predef 
import scala.runtime._ // Package 

Puisque nous sommes préoccupés par implicits, notez que lorsque vous importez des choses de paquets, les seuls implicits possibles sont singletons. Lorsque vous importez des choses à partir d'objets (singletons), vous pouvez avoir des définitions implicites, des valeurs et des singletons.

À l'heure actuelle, CanBuildFrom impliquent à l'intérieur Predef et LowPriorityImplicits, qui sont concernés par les chaînes. Ils nous permettent d'écrire "this is a string" map (_.toInt).

Ainsi, à l'exception de ces importations automatiques et des importations explicites que vous effectuez, où peut-on trouver un fichier implicite? Un endroit: les objets compagnons de l'instance sur laquelle la méthode est appliquée. Je dis compagnon objet s, au pluriel, car les objets compagnons de tous les traits et classes hérités par la classe de l'instance en question peuvent contenir des implicits pertinents. Je ne suis pas sûr si l'instance elle-même peut contenir un implicite. Pour être honnête, je ne peux pas reproduire cela maintenant, alors je fais certainement une erreur ici. En tout cas, regardez à l'intérieur des objets compagnons.

+0

Daniel - comment puis-je savoir quels objets 'implicites' sont dans la portée à un point donné de mon code? Voilà à quoi se résume la question, je me rends compte. Où est-ce spécifié? En outre, cette question n'a rien à voir avec 'breakOut'. –

+0

En dehors des conversions implicites dans l'objet scala.Predef, vous devez soit définir l'implicite dans la même ou une portée englobante ou vous devez importer explicitement cet implicite. –

+0

"lorsque vous importez des choses à partir de paquets, les seuls implicits possibles sont des singletons" Est-ce encore vrai avec les objets du paquet Scala 2.8? Ils pourraient aussi contenir des defs et vals implicites. –

0
object ArrayBuffer extends SeqFactory[ArrayBuffer] { 
    /** $genericCanBuildFromInfo */ 
    implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArrayBuffer[A]] = new GenericCanBuildFrom[A] 
    def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A] 
} 
Questions connexes