简体   繁体   中英

CanBuildFrom and upper type bound parameters

Here is a minimalistic example:

def map[U[_] <: Traversable[T], T](col: U[T]): U[T] 
    = col.map(identity)

This code does not compile.

type mismatch;
 found   : Traversable[T]
 required: U[T]
    = col.map(identity)

My understanding of the problem is the col.map(identity) where the compiler infers an implicit CanBuildFrom[U[T], T, Traversable[T]] instead of desired CanBuildFrom[U[T], T, U[T]] .

Is there a way to make this code working?

The mechanics of builder type classes in Scala 2.12 is something like so

def foo[CC[x] <: Traversable[x], A, B](as: CC[A], f: A => B)(
  implicit cbf: CanBuildFrom[CC[A], B, CC[B]]
): CC[B] = {
  val bf = cbf()
  as.foreach { a => bf += f(a) }
  bf.result()
}

or using .to method

def foo[CC[x] <: Traversable[x], A, B](as: CC[A], f: A => B)(
  implicit cbf: CanBuildFrom[CC[A], B, CC[B]]
): CC[B] = {
  as.map(f).to[CC]
}

Corresponding Scala 2.13 code might be

def foo[CC[x] <: Iterable[x], A, B](as: CC[A], f: A => B)(
  implicit cbf: BuildFrom[CC[A], B, CC[B]]
): CC[B] = {
  cbf.fromSpecific(as)(as.map(f))
}

or using factory

def foo[CC[x] <: Iterable[x], A, B](as: CC[A], f: A => B)(
  implicit factory: Factory[B, CC[B]]
): CC[B] = {
  as.map(f).to(factory) // equivalent to factory.fromSpecific(as.map(f))
}

The meanings of three type parameters of collection builder type class are

             | source coll | element of target coll | target coll   |
---------------------------------------------------------------------
CanBuildFrom | -From       | -Elem                  | +To           |
BuildFrom    | -From       | -A                     | +C            |
Factory      |             | -A                     | +C            |

Note these builder type classes are just generalised version of the following idea

scala> val bf = List.newBuilder[Int]
val bf: scala.collection.mutable.Builder[Int,List[Int]] = ListBuffer()

scala> bf += 1 += 4
val res0: bf.type = ListBuffer(1, 4)

scala> bf.result()
val res1: List[Int] = List(1, 4)

but in practice we rarely see collections constructed in such way.

Another option instead of BuildFrom is to use cats type classes such as Functor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM