Scala 2.8 CanBuildFrom - PullRequest
       37

Scala 2.8 CanBuildFrom

27 голосов
/ 12 ноября 2009

Исходя из другого вопроса, который я задал, Scala 2.8 прорыв , я хотел бы немного подробнее понять метод Scala TraversableLike[A].map, подпись которого выглядит следующим образом:

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

Обратите внимание на несколько вещей об этом методе:

  • Требуется функция, превращающая каждый A в проходимом в B.
  • Возвращает That и принимает неявный аргумент типа CanBuildFrom[Repr, B, That].

Я могу назвать это следующим образом:

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

То, что я не могу понять , это то, как факт, что That является привязанным к B (то есть, это некоторая коллекция B), обеспечивается компилятор. Параметры типа выглядят независимыми как от сигнатуры выше, так и от сигнатуры самого признака CanBuildFrom:

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

Как компилятор Scala гарантирует, что That не может быть принудительно в нечто, что не имеет смысла?

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

Как компилятор решает, какие неявные CanBuildFrom объекты находятся в области действия для вызова?

Ответы [ 2 ]

29 голосов
/ 12 ноября 2009

Обратите внимание, что второй аргумент map является неявным аргументом. должен быть неявным в области видимости с соответствующими типами, или, в противном случае, вы должны передать такой аргумент.

В вашем примере That должно быть Set[String], B должно быть Int и Repr должно быть List[String]. Следовательно, для этого вам необходим следующий неявный объект в области видимости:

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

Нет такой вещи в области видимости. Кроме того, breakOut не может предоставить его, потому что сам по себе нуждается в неявном CanBuildFrom, первым типом которого может быть любой класс (противоположный вариант Nothing), но в остальном ограниченный другими типами.

Посмотрите, например, на фабрику CanBuildFrom от объекта-компаньона List:

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

Поскольку второй и третий параметры связываются с помощью A, неявный вопрос не будет работать.

Итак, как узнать, где искать такие последствия? Прежде всего, Scala импортирует несколько вещей во все области. Прямо сейчас я могу вспомнить следующий импорт:

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

Поскольку мы обеспокоены последствиями, имейте в виду, что при импорте объектов из пакетов возможны только последствия синглтонов. С другой стороны, когда вы импортируете вещи из объектов (синглетонов), вы можете иметь неявные определения, значения и синглтоны.

Прямо сейчас, есть CanBuildFrom имплики внутри Predef и LowPriorityImplicits, которые связаны со строками. Они позволяют нам писать "this is a string" map (_.toInt).

Итак, если не принимать во внимание этот автоматический импорт и выполняемый вами явный импорт, где еще можно найти неявный? Одно место: сопутствующие объекты экземпляра, к которому применяется метод.

Я говорю сопутствующий объект s во множественном числе, потому что сопутствующие объекты всех признаков и классов, унаследованных классом рассматриваемого экземпляра, могут содержать соответствующие импликации. Я не уверен, что сам экземпляр может содержать неявный. Если честно, я не могу сейчас воспроизвести это, поэтому я, безусловно, совершаю здесь какую-то ошибку.

В любом случае, загляните внутрь сопутствующих объектов.

0 голосов
/ 04 июня 2012
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]
}
...