title: Another Scala CanBuildFrom issue: a collection enrichment operator that wraps another of a different type
body: <p>User Régis Jean-Gilles gracefully answered my previous question where I was struggling with CanBuildFrom and enrichment functions (aka "pimp my library" or "enrich my library"):</p>
  
  <p><a href="https://stackoverflow.com/questions/20650456/creating-an-implicit-function-that-wraps-map-in-scala-with-the-right-type-not/20660742#20660742">Creating an implicit function that wraps map() in Scala with the right type: Not for the faint at heart</a></p>
  
  <p>But this time I've got an even more complicated issue.</p>
  
  <p>I have a function to implement variations on <code>intersectWith</code>, for intersecting collections by their keys. I've managed to make them work like proper collection functions:</p>
  
  <pre><code>implicit class IntersectUnionWithPimp[K, A, Repr](a: GenTraversableLike[(K, A), Repr]) {
  
    /**
     * Intersect two collections by their keys. This is identical to
     * `intersectWith` except that the combiner function is passed the
     * key as well as the two items to combine.
     *
     * @param b Other collection to intersect with.
     * @param combine Function to combine values from the two collections.
     */
    def intersectWithKey[B, R, That](b: GenTraversable[(K, B)])(
        combine: (K, A, B) =&gt; R)(
        implicit bf: CanBuildFrom[Repr, (K, R), That]): That = {
      ...
    }
  
    /**
     * Intersect two collections by their keys. Keep the ordering of
     * objects in the first collection. Use a combiner function to
     * combine items in common. If either item is a multi-map, then
     * for a key seen `n` times in the first collection and `m`
     * times in the second collection, it will occur `n * m` times
     * in the resulting collection, including all the possible
     * combinations of pairs of identical keys in the two collections.
     *
     * @param b Other collection to intersect with.
     * @param combine Function to combine values from the two collections.
     */
    def intersectWith[B, R, That](b: GenTraversable[(K, B)])(
        combine: (A, B) =&gt; R)(
        implicit bf: CanBuildFrom[Repr, (K, R), That]): That =
      a.intersectWithKey(b){ case (_, x, y) =&gt; combine(x, y) }(bf)
  }
  </code></pre>
  
  <p>Now, I currently also have non-<code>CanBuildFrom</code> versions of <code>intersectBy</code> and friends, and these I can't get working as <code>CanBuildFrom</code> versions.</p>
  
  <pre><code>implicit class IntersectUnionByPimp[A](a: Traversable[A]) {
    /**
     * Intersect two collections by their keys, with separate key-selection
     * functions for the two collections. This is identical to
     * `intersectBy` except that each collection has its own key-selection
     * function. This allows the types of the two collections to be
     * distinct, with no common parent.
     *
     * @param b Other collection to intersect with.
     * @param key1fn Function to select the comparison key for the first
     *   collection.
     * @param key1fn Function to select the comparison key for the first
     *   collection.
     * @param combine Function to combine values from the two collections.
     */
    def intersectBy2[K, B, R](b: Traversable[B])(key1fn: A =&gt; K
        )(key2fn: B =&gt; K)(combine: (A, B) =&gt; R): Traversable[R] = {
      val keyed_a = a.map { x =&gt; (key1fn(x), x) }
      val keyed_b = b.map { x =&gt; (key2fn(x), x) }
      keyed_a.intersectWith(keyed_b)(combine).map(_._2)
    }
  
    /**
     * Intersect two collections by their keys. Keep the ordering of
     * objects in the first collection. Use a combiner function to
     * combine items in common. If either item is a multi-map, then
     * for a key seen `n` times in the first collection and `m`
     * times in the second collection, it will occur `n * m` times
     * in the resulting collection, including all the possible
     * combinations of pairs of identical keys in the two collections.
     *
     * @param b Other collection to intersect with.
     * @param keyfn Function to select the comparison key.
     * @param combine Function to combine values from the two collections.
     */
    def intersectBy[K, B &gt;: A](b: Traversable[B])(keyfn: B =&gt; K)(
        combine: (A, B) =&gt; B): Traversable[B] = {
      val keyed_a = a.map { x =&gt; (keyfn(x), x) }
      val keyed_b = b.map { x =&gt; (keyfn(x), x) }
      keyed_a.intersectWith(keyed_b)(combine).map(_._2)
    }
  }
  </code></pre>
  
  <p>The best version so far I can come up with is this:</p>
  
  <pre><code>implicit class IntersectUnionByPimp[A, Repr](a: GenTraversableLike[A, Repr]) {
    def intersectBy2[K, B, R, That](b: Traversable[B])(key1fn: A =&gt; K)(
        key2fn: B =&gt; K)(combine: (A, B) =&gt; R)(
        implicit bf: CanBuildFrom[Repr, R, That]): That = {
      // FIXME! How to make this work while calling `map`?
      // val keyed_a = a.map { x =&gt; (key1fn(x), x) }
      val keyed_a = mutable.Buffer[(K, A)]()
      a.foreach { x =&gt; keyed_a += ((key1fn(x), x)) }
      val keyed_b = b.map { x =&gt; (key2fn(x), x) }
      keyed_a.intersectWith(keyed_b)(combine).map(_._2)
    }
  
    def intersectBy[K, B &gt;: A, That](b: Traversable[B])(keyfn: B =&gt; K)(
        combine: (A, B) =&gt; B)(
        implicit bf: CanBuildFrom[Repr, B, That]): That = {
      // FIXME! How to make this work while calling `map`?
      // val keyed_a = a.map { x =&gt; (keyfn(x), x) }
      val keyed_a = mutable.Buffer[(K, A)]()
      a.foreach { x =&gt; keyed_a += ((keyfn(x), x)) }
      val keyed_b = b.map { x =&gt; (keyfn(x), x) }
      keyed_a.intersectWith(keyed_b)(combine).map(_._2)
  }
  </code></pre>
  
  <p>First, I don't see why I need to rewrite the call to <code>map</code> that produces <code>keyed_a</code> with a mutable Buffer; seems like there must be a better way. But I still get the same sort of error on the bottom line:</p>
  
  <pre><code>[error] /Users/benwing/devel/textgrounder/src/main/scala/opennlp/textgrounder/util/collection.scala:1018: type mismatch;
  [error]  found   : scala.collection.mutable.Buffer[R]
  [error]  required: That
  [error]  Note: implicit method bufferToIndexedSeq is not applicable here because it comes after the application point and it lacks an explicit result type
  [error]       keyed_a.intersectWith(keyed_b)(combine).map(_._2)
  [error]                                                  ^
  </code></pre>
  
  <p>So my questions are:</p>
  
  <ol>
  <li>How to call <code>map</code> on a GenTraversableLike?</li>
  <li>How to make the call to <code>intersectWith</code> work correctly? I know I have to somehow pass in a <code>CanBuildFrom</code> based on the one I received, and I know about <code>mapResult</code> on Builders, but I'm not sure what to do here, or if this is even possible.</li>
  </ol>
  
  <p>An example of <code>intersectBy</code>, which intersects lists of floating-point numbers treating two numbers the same if their integral part is the same, and computing the absolute difference:</p>
  
  <pre><code>scala&gt; List(4.5,2.3,4.2).intersectBy(List(4.6,4.8))(_.toInt){ case (a,b) =&gt; (a - b).abs }
  res2: Traversable[Double] = List(0.09999999999999964, 0.2999999999999998, 0.39999999999999947, 0.5999999999999996)
  </code></pre>
  
  <p>(except that the returned type should be <code>List[Double]</code>)</p>
  
  <p>Thanks for any help.</p>