Scala Extractor unapply called twice - scala

I just discovered that unapply in my extractor is being called twice for some reason.
Anyone know why, and how to avoid it?
val data = List("a","b","c","d","e")
object Uap {
def unapply( s:String ) = {
println("S: "+s)
Some(s+"!")
}
}
println( data.collect{ case Uap(x) => x } )
This produces output:
S: a
S: a
S: b
S: b
S: c
S: c
S: d
S: d
S: e
S: e
List(a!, b!, c!, d!, e!)
The final result is fine but in my real program the unapply is non-trivial, so I certainly don't want to call it twice!

collect takes a PartialFunction as input. PartialFunction defines two key members: isDefinedAt and apply. When collect runs your function, it runs your extractor once to determine if your function isDefinedAt some particular input, and if it is, then it runs the extractor again as part of apply to extract the value.
If there is a trivial way of correctly implementing isDefinedAt, you could implement this yourself by implementing your own PartialFunction explicitly, instead of using the case syntax. or you could do a filter and then map with a total function on the collection (which is essentially what collect is doing by calling isDefinedAt, then apply)
Another option would be to lift the Partial function to a total function. PartialFunction defines lift which turns a PartialFunction[A,B] into a A=>Option[B]. You could use this lifted function (call it fun) to do: data.map(fun).collect { case Some(x) => x }

Actually, this was addressed in 2.11 as a performance bug:
$ skala
Welcome to Scala version 2.11.0-20130423-194141-5ec9dbd6a9 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_06).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val data = List("a","b","c","d","e")
data: List[String] = List(a, b, c, d, e)
scala>
scala> object Uap {
| def unapply( s:String ) = {
| println("S: "+s)
| Some(s+"!")
| }
| }
defined object Uap
scala>
scala> println( data.collect{ case Uap(x) => x } )
S: a
S: b
S: c
S: d
S: e
List(a!, b!, c!, d!, e!)
See the efficiency notes on applyOrElse.
Here's a version for 2.10, where the issue is easily remedied by extension:
object Test extends App {
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom
import scala.collection.immutable.StringLike
implicit class Collector[A, Repr, C <: TraversableLike[A, Repr]](val c: C) extends AnyVal {
def collecting[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(c.repr)
c.foreach(pf.runWith(b += _))
b.result
}
}
val data = List("a","b","c","d","e")
object Uap {
def unapply( s:String ) = {
println("S: "+s)
s match {
case "foo" => None
case _ => Some(s+"!")
}
}
}
val c = Collector[String, List[String], List[String]](data)
Console println c.collecting { case Uap(x) => x }
}
Result:
$ scalac -version
Scala compiler version 2.10.1 -- Copyright 2002-2013, LAMP/EPFL
apm#halyard ~/tmp
$ scalac applyorelse.scala ; scala applyorelse.Test
S: a
S: b
S: c
S: d
S: e
List(a!, b!, c!, d!, e!)
Note that this version of Uap is partial:
scala> val data = List("a","b","c","d","e", "foo")
data: List[String] = List(a, b, c, d, e, foo)
scala> data.map{ case Uap(x) => x }
S: a
S: b
S: c
S: d
S: e
S: foo
scala.MatchError: foo (of class java.lang.String)
I think that if the use case is PF, the code should be partial.

Adding to #stew answer, collect is implemented as:
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
for (x <- this) if (pf.isDefinedAt(x)) b += pf(x)
b.result
}
It uses pf.isDefinedAt(x). Doing scalac -Xprint:typer check.scala (check.scala contains your code). It prints:
....
final def isDefinedAt(x1: String): Boolean = ((x1.asInstanceOf[String]:String): String #unchecked) match {
case check.this.Uap.unapply(<unapply-selector>) <unapply> ((x # _)) => true
case (defaultCase$ # _) => false
}
So as you see, it calls unapply here again. This explains why it prints twice i.e. once to check if it is defined and then next when it is already called in `pf(x).
#som-snytt is right. As of Scala 2.11, collect function in TraversableLike is changed to:
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
foreach(pf.runWith(b += _))
b.result
}
The reason it prints only once is that, internally it calls applyOrElse which checks if it is defined. If yes applies the function there it self (in above case (b += _)). Hence it prints only once.

You can use map instead:
scala> println( data.map{ case Uap(x) => x } )
S: a
S: b
S: c
S: d
S: e
List(a!, b!, c!, d!, e!)
No idea why it works that why.

Related

Adding custom collection operations in scala 2.13 to arbitrary collections of specific types

Note - the operation described below now exists in the standard library as partitionMap but I believe it's still a valid question as to how to achieve more general ends
Question regarding scala 2.13 - how do I consume/construct collections of specific types when adding custom collections operations where I need to restrict the element types of the input collections? e.g. how do I define:
def split[CC[_], A, B](coll: CC[Either[A, B]]): (CC[A], CC[B])
Following the documentation I've managed to achieve this as follows:
import collection.generic.IsIterable
import scala.collection.{BuildFrom, Factory}
class SplitOperation[Repr, S <: IsIterable[Repr]](coll: Repr, itr: S) {
def split[A, B, AS, BS](
implicit bfa: BuildFrom[Repr, A, AS],
bfb: BuildFrom[Repr, B, BS],
ev: itr.A =:= Either[A, B]): (AS, BS) = {
val ops = itr(coll)
val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })
(as, bs)
}
}
implicit def SplitOperation[Repr](coll: Repr)(implicit itr: IsIterable[Repr]): SplitOperation[Repr, itr.type] =
new SplitOperation(coll, itr)
However, I need to supply types at the use-site otherwise I get diverging implicit expansion.
scala> List(Left("bah"), Right(1), Left("gah"), Right(2), Right(3))
res1: List[scala.util.Either[String,Int]] = List(Left(bah), Right(1), Left(gah), Right(2), Right(3))
scala> res1.split
^
error: diverging implicit expansion for type scala.collection.BuildFrom[List[scala.util.Either[String,Int]],A,AS]
But the following works:
scala> res1.split[String, Int, List[String], List[Int]]
res4: (List[String], List[Int]) = (List(bah, gah),List(1, 2, 3))
EDIT
class SplitOperation[X, CC[_], S <: IsIterable[CC[X]]](coll: CC[X], itr: S) {
def split[A, B](implicit bfa: BuildFrom[CC[X], A, CC[A]], bfb: BuildFrom[CC[X], B, CC[B]], ev: itr.A =:= Either[A, B]): (CC[A], CC[B]) = {
val ops = itr(coll)
val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })
(as, bs)
}
}
implicit def SplitOperation[A, B, CC[_]](coll: CC[Either[A, B]])(implicit itr: IsIterable[CC[Either[A, B]]]): SplitOperation[Either[A, B], CC, itr.type] =
new SplitOperation(coll, itr)
Gives me a slight improvement. Now I only need to provide type parameters A and B at the call site:
scala> l.split[String, Int]
res2: (List[String], List[Int]) = (List(bah, gah),List(1, 2))
This seems to work:
class SplitOperation[A, B, CC[_], S <: IsIterable[CC[Either[A, B]]]](coll: CC[Either[A, B]], itr: S) {
def split(implicit bfa: BuildFrom[CC[Either[A, B]], A, CC[A]], bfb: BuildFrom[CC[Either[A, B]], B, CC[B]], ev: itr.A =:= Either[A, B]): (CC[A], CC[B]) = {
val ops = itr(coll)
val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })
(as, bs)
}
}
implicit def SplitOperation[A, B, CC[_]](coll: CC[Either[A, B]])(implicit itr: IsIterable[CC[Either[A, B]]]): SplitOperation[A, B, CC, itr.type] =
new SplitOperation(coll, itr)
In your case you don’t want to abstract over the “kind” of the collection type constructor (CC[_] vs CC[_, _], etc.), you always use the CC[_] kind, so you don’t need to use IsIterable.
I think it is also not necessary to support “Sorted” collections (eg, SortedSet) because there is no Ordering instance for Either, so you don’t need to use BuildFrom.
implicit class SplitOperation[A, B, CC[X] <: IterableOps[X, CC, CC[X]]](coll: CC[Either[A, B]]) {
def split: (CC[A], CC[B]) = {
val as = coll.iterableFactory.from(coll.iterator.collect { case Left(a) => a })
val bs = coll.iterableFactory.from(coll.iterator.collect { case Right(b) => b })
(as, bs)
}
}
https://scastie.scala-lang.org/64QxHwteQN2i3udSxCa3yw

for comprehension fails when using an intermediate variable

Scastie version
With this infra-structure:
trait Pat[A]
object Pat {
def apply[A](elems: A*): Pat[A] = ???
}
implicit class PatOps[A](p: Pat[A]) {
def ++ (that: Pat[A]): Pat[A] = ???
def bubble: Pat[Pat[A]] = ???
def grouped(size: Pat[Int]): Pat[Pat[A]] = ???
}
implicit class PatPatOps[A](p: Pat[Pat[A]]) {
def map[B](f: Pat[A] => Pat[B]): Pat[Pat[B]] = ???
def flatMap[B](f: Pat[A] => Pat[B]): Pat[B] = ???
def flatten: Pat[A] = ???
}
It is possible to write the following for-comprehension:
trait Test1 {
val lPat = Pat(1, 2, 3)
val xs = for {
len <- lPat.bubble
cantus <- Pat(4, 40, 3).grouped(len)
} yield {
cantus ++ Pat(-1)
}
xs.flatten
}
But this one, using an intermediate variable, fails:
trait Test2 {
val lPat = Pat(1, 2, 3)
val xs = for {
len <- lPat.bubble // XXX
brown = Pat(4, 40, 3)
cantus <- brown.grouped(len)
} yield {
cantus ++ Pat(-1)
}
xs.flatten
}
The error for the line marked XXX is:
type mismatch;
found : (Playground.this.Pat[Int], Playground.this.Pat[Int])
required: Playground.this.Pat[?]
Scala is 2.12.4
This happens when you define map with overly restrictive signature map[B](f: Pat[A] => Pat[B]). Recall that usually, it is supposed to accept functions with arbitrary result type B, that is, it's supposed to be rather something like:
map[B](f: A => B): <stuff>
Now, your for-comprehension with intermediate helper variable brown
val xs = for {
len <- lPat.bubble
brown = Pat(4, 40, 3)
cantus <- brown.grouped(len)
} yield {
cantus ++ Pat(-1)
}
is rewritten using a map into
val xs = lPat.bubble.map(((len) => {
val brown = Pat(4, 40, 3);
scala.Tuple2(len, brown)
})).flatMap(((x$1) => x$1: #scala.unchecked match {
case scala.Tuple2((len # _), (brown # _)) =>
brown.
grouped(len).
map(((cantus) => cantus.$plus$plus(Pat(-1))))
}))
as described in the documentation or in my overly detailed answer here.
Note how the return type of the implicitly generated map is now something like (Pat[A], Pat[Int]) (the type of the tuple (len, brown)), and doesn't match the pattern Pat[B] from your declaration.
I don't see any workarounds. Just do whatever you can to avoid defining map as map[B](f: Pat[A] => Pat[B]), otherwise it will behave way too strangely. Avoid breaking functoriality of map. If your Pat[X] cannot map f: X => Y to a Pat[Y] for arbitrary X and Y, then don't call it map.
Edit: there is always a work-around...
One thing you could do is to introduce some kind of implicitly supplied CanPatFrom:
trait CanPatFrom[X, A] extends (X => Pat[A])
and then
...
def map[X, B](f: Pat[A] => X)(implicit cpf: CanPatFrom[X, B]) = {
val pb: Pat[B] = cpf(f(...))
/* do your stuff here with `Pat[B]` instead of
* generic `X`
*/
...
}
Assuming that your Pat carries some kind of cartesian-monoidal structure, you could define
CanPatFrom[Pat[A], Pat[A]],
CanPatFrom[(Pat[A], Pat[B]), Pat[(A, B)]],
CanPatFrom[(Pat[A], Pat[B], Pat[C]), Pat[(A, B, C)]],
...
and thereby obtain a map that can at least cope with the case that the return type is a tuple.
Riffing off of Andrey Tyukin's answer, another thing you can do with implicits is assert that some type parameter satisfies some constraint. For example, we can assert that a parameter A is a subclass of Pat[A1] for some other parameter A1. Here's the code:
object Pats extends App {
trait Pat[A]
object Pat {
def apply[A](elems: A*): Pat[A] = ???
}
implicit class PatOps[A](p: Pat[A]) {
def ++(that: Pat[A]): Pat[A] = ???
def bubble: Pat[Pat[A]] = ???
def grouped(size: Pat[Int]): Pat[Pat[A]] = ???
def map[B, A1, B1](f: A => B)
(implicit
ev1: A <:< Pat[A1],
ev2: B <:< Pat[B1]): Pat[B] = ???
def flatMap[B, A1, B1](f: A => Pat[B])
(implicit
ev1: A <:< Pat[A1],
ev2: B <:< Pat[B1]): Pat[B] = ???
def flatten[A1](implicit ev: A <:< Pat[A1]): Pat[A1] = ???
}
val lPat = Pat(1, 2, 3)
val xs = for {
len <- lPat.bubble
cantus <- Pat(4, 40, 3).grouped(len)
} yield cantus ++ Pat(-1)
xs.flatten
}
I wouldn't recommend taking this approach, though, because it violates the usual meaning of map and flatMap. What I might suggest instead is creating a private class PatInternal and completely obfuscate it from the end user.

How does orElse work on PartialFunctions

I am getting very bizarre behavior (at least it seems to me) with the orElse method defined on PartialFunction
It would seem to me that:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing
makes sense but this is not how it is behaving and I am having a lot of trouble understanding why as the types signatures seem to indicate what I exposed above.
Here is a transcript of what I am observing with Scala 2.11.2:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> a("hello")
Bye
scala> a("bye")
scala.MatchError: bye (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
... 33 elided
scala> val b = a.orElse(PartialFunction.empty[Any, Unit])
b: PartialFunction[String,Unit] = <function1>
scala> b("sdf")
scala.MatchError: sdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
Note the return type of val b which has not widen the type of the PartialFunction.
But this also does not work as expected:
scala> val c = a.orElse(PartialFunction.empty[String, Unit])
c: PartialFunction[String,Unit] = <function1>
scala> c("sdfsdf")
scala.MatchError: sdfsdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
There's a few things wrong with your attempt, but first let's see a working implementation:
scala> val a: PartialFunction[String, Unit] = { case "hello" => println("bye") }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[Any, Unit] = { case _ => println("fallback") }
b: PartialFunction[Any,Unit] = <function1>
scala> val c = a.orElse(b)
c: PartialFunction[String,Unit] = <function1>
scala> c("hello")
bye
scala> c("foo")
fallback
There's two main errors in your code:
the way the PF is defined
the (wrong) assumption that empty is a "catch-all" function that returns Nothing
1. How to define a PartialFunction
val right: PartialFunction[String, Unit] = {
case "hello" => println("bye")
}
How not to define it:
val wrong = PartialFunction[String, Unit] {
case "hello" => println("bye")
}
If you look at the definition of PartialFunction.apply
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
you'll see that it defines a partial function for any x and it applies the given f function to it. Now your { case "hello" => println("bye") } is the f argument, so you approximately end up with the following (clearly unexpected) PartialFunction:
val wrong: PartialFunction[String, Unit] = {
case x => x match {
case "hello" => println("bye")
}
So when you ask whether it's defined it will always return true, since it's defined for any string:
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)
but when you try to apply it
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)
you fall short on the inner match.
Since orElse decides whether to call the "else" depending on the result of isDefined, then it's obvious why it fails.
2. Empty catches nothing!
Straight from the docs:
def empty[A, B]: PartialFunction[A, B]
The partial function with empty domain. Any attempt to invoke empty partial function leads to throwing scala.MatchError exception.
The PartialFunction (well, it's not really partial anymore) you're looking for is:
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
or - just to show that we learn from our mistakes -
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
You are using the PartialFunction object apply method which is defined so:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
Basically it takes a function form A to B and automatically wrap it in a case statement, the problem is that you are passing the case too and I'm not 100% sure of what happens then, you can try passing a function to the apply or easily you can try without using the apply method:
scala> val a: PartialFunction[String, Unit] = {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[String, Unit] = {
| case _ => println("default")
| }
b: PartialFunction[String,Unit] = <function1>
scala> b("123")
default
You could also extend the trait and implement apply and isDefined as shown here.
PartialFunction.empty[A,B] is equivalent to:
{
case x: Nothing => x
}
(This typechecks, because Nothing is a subtype of both A and B.)
or, equivalently:
{
// note: this is probably not a valid Scala code for a partial function
// but, as PartialFunction.empty's name suggests, it's an *empty* block
}
This cannot match anything.
.orElse can be understood to simply concatenates lists of case statements from two PartialFunctions. So, in your case a.orElse(PartialFunction.empty[Any,Unit] means:
{ case "hello" => println("Bye") } orElse { /* no cases here */ }
which simplifies to:
{ case "hello" => println("Bye") }
or
{ case "hello" => println("Bye"); case x:Nothing => x }
MatchError is therefore obvious.
Note that the documetation also mentions that empty always throws MatchError.
From what I can guess, you wanted a PartialFunction that always matches. There's no named method in the standard library for that, but why should there be. You can simply write
{ case _ => () }

Tupled function outputs

I'm looking for a function that takes a tuple of functions over a common domain and returns a function from that domain to a tuple of their respective outputs. I'm assuming that such a utility is either built into Scala or is tucked away somewhere in Scalaz, but I have been unable to find it.
For example, the special case of a pair of functions (and taking the functions as individual arguments rather than a pair) would look like:
def pairFunc[I, O1, O2](f: I => O1, g: I => O2): I => (O1, O2) = (x: I) => (f(x), g(x))
Is there a way to achieve this for an arbitrary-arity tuple of functions?
EDIT:
A method on a Function type whose output looks like X -> ((A, B), C) and whose construction looks like f fZip g fZip h is just as fine as one a function whose output is X -> (A, B, C).
You're in luck, scalaz (7) does have this with &&&:
import scalaz._
import Scalaz._
val intToString = (i:Int) => i.toString
val intPlusTwo = (i:Int) => i + 2
val combined = intToString &&& intPlusTwo
println(combined(1)) // (1, 3)
And you can continue to combine though it does build up tuples per what your comments would suggest:
val combinedMore = intToString &&& intPlusTwo &&& intToString
println(combinedMore(1)) // ((1,3),1)
You can define your own implicits and chain them using view bounds <%
// Add untupling capacity to a simple pair
implicit class EnrichTuple [A, B, C](f: (Function1[A, B], Function1[A, C])) {
def untuple = (a: A) => (f._1(a), f._2(a))
}
// Add untupling capacity to a pair where the first member can implicitly be untupled
implicit class EnrichTuple2 [A, C, AB <% Function1[A, B] forSome { type B }](f: (AB, Function1[A, C])) {
def untuple = (a: A) => (f._1(a), f._2(a))
}
// Add untupling capacity to a pair where the second member can implicitly be untupled
implicit class EnrichTuple3 [A, B, AC <% Function1[A, C] forSome { type C }](f: (Function1[A, B], AC)) {
def untuple = (a: A) => (f._1(a), f._2(a))
}
val intToString = (i:Int) => i.toString
val intPlusTwo = (i:Int) => i + 2
val intTimesFour = (i: Int) => i * 4
val res1 = (intToString, intPlusTwo).untuple
val res2 = ((intToString, intPlusTwo), intTimesFour).untuple
val res3 = (intToString, (intPlusTwo, intTimesFour)).
res1(1) // Returns (1, 3)
res2(1) // Returns ((1, 3),4)
res3(1) // Returns (1, (3, 4))
val res4 = ((intToString, intTimesFour), (intPlusTwo, intTimesFour )).untuple // Error
The thing you also loose compared to the scalaz solution is the type of the result if there are nested tuples. And besides, you have the requirement that each time at least one of the two arguments of your pair is already a function.

How to enrich Scala collections with my own generic `map` (the right way)?

I'm trying to enrich Scala collections with my own map method, and I'm close but the implicit conversion doesn't work. Besides that, is there anything else I'm missing here? I'm looking at various other resources on the Web, including SO answers that this question is being marked as duplicating, and many are missing something here and there (e.g. using C[A] <: GenTraversable[A], using b() instead of b(xs), forgetting about Array, forgetting about BitSet, etc.).
implicit def conv[A,C](xs: C)(implicit ev: C <:< GenTraversableLike[A,C]) = new {
def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[C,B,D]): D = b(xs).result // placeholder
}
scala> conv(List(1,2,3))
res39: java.lang.Object{def mymap[B,D](f: Int => B)(implicit b: scala.collection.generic.CanBuildFrom[List[Int],B,D]): D} = $$$$2c9d7a9074166de3bf8b66cf7c45a3ed$$$$anon$1#3ed0eea6
scala> conv(List(1,2,3))mymap(_+1)
res40: List[Int] = List()
scala> conv(BitSet(1,2,3))mymap(_+1)
res41: scala.collection.immutable.BitSet = BitSet()
scala> conv(BitSet(1,2,3))mymap(_.toFloat)
res42: scala.collection.immutable.Set[Float] = Set()
scala> List(1,2,3)mymap(_+1)
<console>:168: error: Cannot prove that List[Int] <:< scala.collection.IterableLike[A,List[Int]].
List(1,2,3)mymap(_+1)
^
scala> implicit def conv[A, C](xs: C)(implicit ev: C => GenTraversable[A]) = new {
| def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[GenTraversable[A],B,D]): D =
| xs map f
| }
conv: [A, C](xs: C)(implicit ev: C => scala.collection.GenTraversable[A])java.lang.Object{def mymap[B,D](f: A => B)(implicit b: scala.collection.generic.CanBuildFrom[scala.collection.GenTraversable[A],B,D]): D}
scala> conv(Array(1)) mymap (_+1)
res6: scala.collection.GenTraversable[Int] = ArrayBuffer(2)
scala> Array(1) mymap (_+1)
<console>:68: error: No implicit view available from Array[Int] => scala.collection.GenTraversable[A].
Array(1) mymap (_+1)
^
I've answered this very question about type inference just last week. Here's the code:
implicit def conv[A,C <: GenTraversable[A]](xs: C with GenTraversableLike[A,C]) = new {
def mymap[B,D](f: A => B)(implicit b: CanBuildFrom[C,B,D]): D = {
val builder = b(xs)
xs foreach { x => builder += f(x) }
builder.result
}
}
I could have used GenTraversable instead of GenTraversableLike in this particular case. I prefer the later because it offers more.
The problem is that declaring [A, C <: GenTraversable[A]] does not instruct Scala to infer the type of A from the type of C. Types are inferred based on how they are used in the parameters, and then checked against the boundaries specified by the type parameters.
So when I write xs: C with GenTraversable[A], I let Scala know it should infer A from xs. And writing GenTraversableLike[A, C] tells Scala it should pick a collection that returns C for methods that return the same collection. This means you can call filter and get C back, instead of getting GenTraversable back.
As for wishing to include views, that I don't know how you could accomplish.
I have answered a similar question here. You can also refer to this thread where Rex Kerr explains how to perform such pimping in general.