2009-11-12 10 views
26

A raíz de otra pregunta que hice, Scala 2.8 breakout, quería entender un poco más sobre el método Scala TraversableLike[A].map cuya firma es el siguiente:Scala 2,8 CanBuildFrom

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

Aviso algunas cosas acerca de este método :

  • Se toma una función girando cada A en el desplazable en un B.
  • Devuelve That y toma un argumento implícito del tipo CanBuildFrom[Repr, B, That].

puedo llamar a esto de la siguiente manera:

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

Lo No puedo logran entender es como el hecho de que That es obligado-B (es decir, que es parte de la recopilación de B) está siendo aplicado por el compilador. Los parámetros de tipo parecen ser independiente tanto de la firma anterior y de la firma del rasgo CanBuildFrom sí:

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

¿Cómo es el compilador de Scala asegurando que That no puede ser forzada en algo que no tiene sentido?

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

¿Cómo decidir el compilador lo CanBuildFrom objetos implícitos están en el ámbito de la llamada?

+0

Aquí está el post con una explicación bastante bien http://blog.bruchez.name/2012/08/getting-to-know-canbuildfrom-without-phd.html –

+0

Para el registro, tal uso tiene un nombre conceptual: polimorfismo de tipo de retorno. – lcn

Respuesta

29

Tenga en cuenta que el segundo argumento para map es un argumento implícito. Hay debe ser un alcance implícito con los tipos apropiados, o, de lo contrario, debe pasar tal argumento.

En su ejemplo, debe haber ThatSet[String], B debe ser Int y Repr debe ser List[String]. Por lo tanto, para que eso necesita compilar el siguiente objeto implícito en su alcance:

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

No hay tal cosa en su alcance. Además, breakOut no puede proporcionarlo, ya que, en sí mismo, necesita un CanBuildFrom implícito, cuyo primer tipo puede ser cualquier clase (un descendiente contra-variante de Nothing), pero restringido por los otros tipos.

echar un vistazo, por ejemplo, en la fábrica de CanBuildFrom del objeto compañero de List:

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

porque se une el segundo y tercer parámetro a través A, lo implícito en cuestión no va a funcionar.

Entonces, ¿cómo sabe uno dónde buscar, con respecto a tales implicits? En primer lugar, Scala sí importa algunas cosas en todos los ámbitos.En este momento, puedo recordar las siguientes importaciones:

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

Como nos preocupa implícitos, tenga en cuenta que al importar cosas de paquetes, las únicas posibles implícitos son únicos. Cuando importa cosas desde objetos (singletons), por otro lado, puede tener definiciones implícitas, valores y singletons.

En este momento, hay implicitos CanBuildFrom dentro de Predef y LowPriorityImplicits, que se refieren a las cadenas. Nos permiten escribir "this is a string" map (_.toInt).

Entonces, salvo estas importaciones automáticas, y las importaciones explícitas que realiza, ¿dónde más se puede encontrar un implícito? Un lugar: los objetos complementarios de la instancia en la que se aplica el método.

Digo el objeto compañero s, en plural, porque los objetos complementarios de todos los rasgos y clases heredados por la clase de la instancia en cuestión pueden contener implícitos relevantes. No estoy seguro de si la instancia en sí puede contener un implícito. Para ser sincero, no puedo reproducir esto ahora mismo, así que ciertamente estoy cometiendo un error de algún tipo aquí.

En cualquier caso, busque dentro de los objetos complementarios.

+0

Daniel: ¿cómo puedo saber qué objetos 'implícitos' están en el alcance en un punto dado de mi código? A eso se reduce la pregunta, me doy cuenta. ¿Dónde está especificado? Además, esta pregunta no tiene nada que ver con 'breakOut'. –

+0

Además de las conversiones implícitas en el objeto scala.Predef, debe definir lo implícito en el mismo ámbito o en el que lo incluye o debe importarlo explícitamente. –

+0

"cuando importa cosas desde paquetes, las únicas implícitas posibles son simples" ¿Sigue siendo cierto con los objetos del paquete Scala 2.8? Podrían contener defs y val implícitos también. –

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] 
} 
Cuestiones relacionadas