Implicit conversion of Traversable contents in Scala - scala

I am trying to create an implicit converter that would would use a implicit converter that's currently in scope (eg. A => B) and would be able to convert any type of Traversable[A] to Traversable[B].
So far I got:
implicit def convertLists[A, B](from: Traversable[A])(implicit conv: A => B): Traversable[B] = from.map(conv)
This however does not work with:
val listOfB: List[B] = convertLists(List[A]())
If I change Traversable to List, then it works fine, eg:
implicit def convertLists[A, B](from: List[A])(implicit conv: A => B): List[B] = from.map(conv)
Do I need to add anything else to allow the converter to accept any subclass of Traversable?

You have explicitly defined convertLists to return Traversable[B]. Traversable is not a subtype of List (it's its supertype), so the result of convertLists (Traversable) can't be a return type of listOfB (List).
You can define convertLists to infer the result type based on the type of its argument, if you use CanBuildFrom:
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
// `CC` is some concrete subtype of `Traversable`
// `That` is an automatically inferred result collection type
implicit def convertLists[A, B, CC[T] <: TraversableLike[T, CC[T]], That](
from: CC[A]
)(
implicit
conv: A => B,
// witness that it's possible to build
// a collection with elements `B` from a collection `CC[A]`,
// and compute the resulting collection type `That`
bf: CanBuildFrom[CC[A], B, That]
): That = from.map(conv)
Now assuming the following simple definition of A and B
case class A(i: Int)
case class B(i: Int)
implicit def aisb(a: A): B = B(a.i)
The following works:
val listOfB: List[B] = convertLists(List[A](A(1)))
And you don't have to call convertLists explicitly:
val listOfB2: List[B] = List[A](A(1))

Using the approach in scala collections library you could come out with such code:
import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike
implicit val boolToInt = (b: Boolean) => if (b) 1 else 0
implicit def convertLists[A, B, Repr, That](from: TraversableLike[A, Repr])(implicit conv: A => B, bf: CanBuildFrom[Repr, B, That]): That = from map conv
val listOfB: List[Int] = List(true, false)
which gives
listOfB: List[Int] = List(1, 0)

Related

how to call filter on both Seq an Vector

I'd like to make a method that take a vector or a seq of of some type, let's say Int, and calls filter on it.
For example:
implicit class SharedOps[F](xs: F)(implicit ev: OneOf[F, Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: Int):F = xs.filter({a:Int => a == x})
}
OneOf basically checks that F is either a Seq[Int] or a Vector[Int]
The tricky part is that I want the filter to return the same type as the input (e.g. Seq[Int] or Vector[Int]) but compiler is complaining
error: type mismatch;
found : scala.this.Function1[scala.this.Int,scala.this.Boolean]
required: scala.this.Int
def filter(x: Int):F = xs.filter({a:Int => a == x})
Somehow compiler forgot I started with a collection of sorts and thinks xs is a single thing.
So I changed the design:
implicit class SharedOps2[A,F[A]<:TraversableLike[A,A]](xs: F[A])(implicit ev: OneOf[F[A], Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: A): F[A] = xs.filter({ a: Int => a == x })
}
Now compiler is complaining that: Expression of type A doesn't conform to expected type F[A]
Not sure how to take it from here. I'd like to avoid shapeless coproducts at this point.
For completeness here's the OneOf code:
sealed trait HSubset // HList
#implicitNotFound("No member of type class HSubset in scope for ${H}")
trait :::[+H, +T <: HSubset] extends HSubset // HCons ::
sealed trait HSNil extends HSubset // HNil
#implicitNotFound("No member of type class BelongsTo in scope for ${T}")
trait BelongsTo[T, U <: HSubset]
object BelongsTo {
implicit def baseCase[H, U <: HSubset]: BelongsTo[H, H ::: U] = null
implicit def recursiveCase[H, U <: HSubset, T](implicit ev: T BelongsTo U): T BelongsTo (H ::: U) = null
}
#implicitNotFound("No member of type class SubsetOf in scope for ${U} ${T}")
trait SubsetOf[U <: HSubset, T <: HSubset]
object SubsetOf {
implicit def baseCase[U1, U <: HSubset](implicit s: U1 BelongsTo U): SubsetOf[U1 ::: HSNil, U] = null
implicit def recursiveCase[U <: HSubset, T1, T <: HSubset](implicit ev1: T1 BelongsTo U, ev2: T SubsetOf U): (T1 ::: T) SubsetOf U = null
}
trait OneOf[T, U <: HSubset]
object OneOf {
implicit def baseCase[U <: HSubset, T](implicit s: T BelongsTo U): T OneOf U = null
implicit def recursiveCase[T, Ev <: HSubset, Target <: HSubset](implicit ev1: T OneOf Ev, ev2: Ev SubsetOf Target): T OneOf Target = null
}
This is the proposed typeclas.
My advice would be to use specific types like List & Vector instead of Seq.
trait Filter[F[_]] {
def filter[A](fa: F[A])(p: A => Boolean): F[A]
}
object Filter {
implicit final val VectorFilter: Filter[Vector] =
new Filter[Vector] {
override final def filter[A](vector: Vector[A])(p: A => Boolean): Vector[A] =
vector.filter(p)
}
implicit final val SeqFilter: Filter[Seq] =
new Filter[Seq] {
override final def filter[A](seq: Seq[A])(p: A => Boolean): Seq[A] =
seq.filter(p)
}
}
object syntax {
object filter {
implicit class FilterOps[F[_], A](private val fa: F[A]) extends AnyVal {
#inline
final def filter(p: A => Boolean)(implicit ev: Filter[F]): F[A] =
ev.filter(fa)(p)
}
}
}
import syntax.filter._
def foo[F[_] : Filter](xs: F[Int]): F[Int] =
xs.filter(i => (i % 2) == 0)
Which you can use like:
foo(Vector(1, 2, 3))
// res: Vector[Int] = Vector(2)
foo(List(1, 2, 3))
// could not find implicit value for evidence parameter of type ammonite.$sess.cmd0.Filter[List]
foo(Seq(1, 2, 3))
// res: Seq[Int] = List(2)
BTW, it is worth mentioning that such typeclass already exists in cats
TraversableLike.filter returns Repr, which is type passed as second type parameter to TraversableLike. You need F[A] there instead of A. This compiles for me:
implicit class SharedOps2[A,F[A]<:TraversableLike[A,F[A]]](xs: F[A])(implicit ev: OneOf[F[A], Seq[A] ::: Vector[A] ::: HSNil]) {
def filter(x: A): F[A] = xs.filter({ a: A => a == x })
}
Note also type of a changed to A, because this is the type inside F[A] collection.
fiddle

Functor implementation for types with more than one type

let's say I have:
trait Get[F[_], A, B]{
def get(a:A): F[B]
}
I want to be able to map over the result type B, ie I want to be able to do:
val getFoo: Get[IO, String, Foo] = ???
val foo2Bar: Foo => Bar = ???
val getBar: Get[IO, String, Bar] = getFoo.map(foo2Bar)
I understand that I should implement a Functor instance for Get but I am struggling as I don't know what type signature to use.
I tried the following:
implicit val functor:Functor[Get] = ???
implicit val functor: Functor[Lambda[(F[_], K, A) => Get[F, K, A]]] = ???
but they don't seem to be of the right type as I can't seem to use the functor syntax extension as illustrated at the top. What is the right way of expressing the type here? What would be the equivalent type be if I use the kind-projector plugin?
Try
import cats.syntax.functor._
implicit def functor[F[_]: Functor, A]: Functor[Get[F, A, ?]] = new Functor[Get[F, A, ?]] {
override def map[B, B1](fa: Get[F, A, B])(f: B => B1): Get[F, A, B1] = a => fa.get(a).map(f)
}

How to construct an empty Iterable subclass, generically, and in Scala.js

Normally breakout would aid in conversion from one collection to another, but it doesn't seem to be able to infer the necessary colleciton constuctor for C:
import scala.collection.breakOut
object Utils {
implicit class IterableExtra[T, C[X] <: Iterable[X]](val list: C[T]) extends AnyVal {
def empty: C[T] = Iterable.empty[T].map(x => x)(breakOut)
}
}
Ideally this would work with minimal reflection, so that it might work in scala.js
Update I was also trying to use this in a different way, and I forgot to have the implicit at the outermost level:
def testIterableEmpty[B, I[X] <: Iterable[X]](implicit cbf: CanBuildFrom[I[B], B, I[B]]): I[B] = {
def emptyIter: I[B] = cbf().result()
emptyIter
}
scala> val x: List[Int] = testIterableEmpty[Int, List]
x: List[Int] = List()
breakOut is defined like so:
def breakOut[From, T, To](implicit b: CanBuildFrom[Nothing, T, To]): CanBuildFrom[From, T, To]
So it cannot be used to avoid passing a CanBuildFrom into your empty method - it requires one itself. Luckily, it is easy to write - you want to create a C[T] out of C[T], and the element type is T, so:
def empty(implicit cbf: CanBuildFrom[C[T], T, C[T]]): C[T] =
Iterable.empty[T].map(x => x)(breakOut)
Tho since you have a CanBuildFrom instance anyway, the implementation using it directly is straightforward too:
def empty(implicit cbf: CanBuildFrom[C[T], T, C[T]]): C[T] =
cbf().result()

Scala: implicitly convert Option to Option of implicit class [duplicate]

I'm trying to write a function which re-uses the implicit conversions which I have for Object A -> Object B when they are wrapped in an Option in a generic way so that Option[A] -> Option[B] conversions also work.
What I've come up with is:
implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
This works when I assign a Some(..) to a value but not when I assign an Option val; see the following console output:
scala> trait T
defined trait T
scala> case class Foo(i: Int) extends T
defined class Foo
scala> case class Bar(i: Int) extends T
defined class Bar
scala> implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
fromFooToBar: (f: Foo)Bar
scala> implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
fromBarToFoo: (b: Bar)Foo
scala> implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
fromOptionToOption: [A, B](from: Option[A])(implicit conversion: (A) => B)Option[B]
scala> val foo: Option[Foo] = Some(Bar(1))
foo: Option[Foo] = Some(Foo(1))
// THIS WORKS as expected
scala> val fooOpt = Some(Foo(4))
fooOpt: Some[Foo] = Some(Foo(4))
scala> val barOpt2: Option[Bar] = fooOpt
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
//THIS FAILS.
I don't really see the difference between the first and second conversion. Somehow it doesn't invoke the implicit conversion in the latter. I guess it has something to do with the type system, but I can't see how just yet. Any ideas?
-Albert
(I'm on scala 2.9.1)
Here's clue:
scala> val fooOpt: Option[Bar] = Option(Foo(1))
fooOpt: Option[Bar] = Some(Bar(1))
And another:
scala> implicit def foobar(x: String): Int = augmentString(x).toInt
foobar: (x: String)Int
scala> val y: Option[String] = Option(1)
y: Option[String] = Some(1)
scala> val y: Option[Int] = Option("1")
y: Option[Int] = Some(1)
Looks like a legitimately odd bug. I'd pop open a smaller test case and open an issue (or search for one in JIRA).
As an aside:
You could use some category theory to handle lots of different types of "Option-ish" things.
package object fun {
trait Functor[Container[_]] {
def fmap[A,B](x: Container[A], f: A => B): Container[B]
}
object Functor {
implicit object optionFunctor extends Functor[Option] {
override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f
}
// Note: With some CanBuildFrom magic, we can support Traversables here.
}
implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] =
functor.fmap(x,f)
}
That's a bit more advanced, as you're mapping some category theory FP onto the problem, but it's a more general solution to lift implicit conversations into containers as needed. Notice how they chain by using one implicit conversation method that takes a more limited implicit argument.
ALSO, this should make the examples work:
scala> val tmp = Option(Foo(1))
tmp: Option[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
y: Option[Bar] = Some(Bar(1))
And make your usage of Some more dangerous:
scala> val tmp = Some(Foo(1))
tmp: Some[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
<console>:25: error: could not find implicit value for parameter functor: fun.Functor[Some]
val y: Option[Bar] = tmp
^
That's telling you that variance is critical, and interacts with implicits. My guess is you ran into a very rare, probably hard to fix bug that can be avoided using other techniques.
You might not be aware of it, but there's a flag for that: -Xlog-implicits. And this is what it says:
scala> val barOpt2: Option[Bar] = fooOpt
fromOptionToOption is not a valid implicit value for Some[Foo] => Option[Bar] because:
incompatible: (from: Option[Foo])(implicit conversion: Foo => B)Option[B] does not match expected type Some[Foo] => Option[Bar]
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
And there you go -- it doesn't know what type B must be. 0__ mentioned that this problem doesn't happen with invariant collections, and that makes some sense. In invariant collections, B must be exactly Bar, while for covariant collections it could be any subtype of Bar.
So, why does val foo: Option[Foo] = Some(Bar(1)) work? Well, there's a flag for that too... -Ytyper-debug. Not for the weak, however, given the extreme verbosity.
I waddled through anyway, comparing what happens in both cases, and the answer is rather simple... it's not the Option that is being converted in that case, but Bar! Remember, you declared an implicit conversion from Bar => Foo, so it is applying that conversion before passing the result to Some!
It doesn't work because the Scala Language Specification defines view as follows:
Implicit parameters and methods can also define implicit conversions called views. A view from type S to type T is defined by an implicit value which has function type S=>T or (=>S)=>T or by a method convertible to a value of that type.
fromOptionToOption doesn't conform to the three categories since it takes an implicit parameter. Compiler doesn't seem to find converter with both destination and source having generic type.
Defining a view from Option[Foo] to Option[Bar] works as expected.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
// implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] =
// from.map(conversion(_))
implicit def fromOptionFooToOptionBar(o: Option[Foo]): Option[Bar] = o map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Running this prints out:
$ scala so.scala
Some(Bar(4))
However, all is not lost. It's not as nice as general Option to Option, but we can do something like anything that can turn into Bar to Option[Bar] by view bound.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
implicit def fromOptionToOptionBar[A <% Bar](from: Option[A]): Option[Bar] =
from map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Here's another workaround that can be used for general Option to Option but requires extra .convert call:
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
case class Converter[A](x: Option[A]) {
def convert[B](implicit ev: Function1[A, B]): Option[B] = x map { a: A => ev(a) }
}
object Main {
implicit def optionToConverter[A](x: Option[A]) = Converter(x)
implicit def fooToBar(x: Foo) = Bar(x.i)
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt: Option[Bar] = fooOpt.convert
barOpt
}
}
println(Main.test)
Indeed it's a very strange problem. I tried to use another type than Option, and it turns out that the problem is that Option is covariant in its type parameter. This works all:
case class A[B](value: B) // invariant in B
case class X()
case class Y()
implicit def xtoy(x: X): Y = Y()
implicit def ytox(x: Y): X = X()
implicit def movea[U, V](from: A[U])(implicit view: U => V): A[V] = A[V](from.value)
def test(a: A[Y]) = "ok"
test(A(X())) // (1)
val f = A(X())
test(f) // (2)
But if instead I define A as
case class A[+B](value: B) // covariant in B
The case (2) fails. Case (1) always succeeds, because Scala already converts X to Y before wrapping it in an A.
Now that we know the problem source, you need to wait for a type guru to explain why this is actually a problem... The conversion is still valid, you see:
askForY(movea(f)) // succeeds, even with A[+B]
I improved #jseureth answer and added support for Traversable:
trait Mappable[A, B, C[_]] {
def apply(f: A => B): C[B]
}
package object app {
implicit class OptionMappable[A, B, C[X] <: Option[X]](option: C[A]) extends Mappable[A, B, Option] {
override def apply(f: A => B): Option[B] = option.map(f)
}
implicit class TraversableMappable[A, B, C[X] <: Traversable[X]](traversable: C[A])
(implicit cbf: CanBuildFrom[C[A], B, C[B]]) extends Mappable[A, B, C] {
override def apply(f: A => B): C[B] = {
val builder = cbf(traversable)
builder.sizeHint(traversable)
builder ++= traversable.map(f)
builder.result()
}
}
implicit def liftConversion[C[_], A, B](x: C[A])
(implicit f: A => B, m: C[A] => Mappable[A, B, C]): C[B] = m(x)(f)
}
Now you can implicitly convert options and traversables:
implicit def f(i: Int): String = s"$i"
val a: Option[String] = Some(1)
val b: Seq[String] = Seq(1, 2, 3)

Chain implicit conversion of collection

I fail make an implicit conversion List[A] => List[B], given implicit conversion A => B.
There is a very related question that has a solution but does not work for me. Also, here is a nice documentation for chaining implicits, which I used as the base of my code below.
The point I try to make in the code below is that chaining implicits works fine in all expected cases, even for collection-like objects like the Container below, but fails for collections:
object ChainImplicits extends App{
case class A(n: Int)
implicit def toA(n: Int): A = A(n)
case class B(m: Int, n: Int)
implicit def aToB[T](a: T)(implicit f: T => A): B = B(a.n, a.n)
case class C(m: Int, n: Int, o: Int) {
def total = m + n + o
}
implicit def bToC[T](b: T)(implicit f: T => B): C = C(b.m, b.n, b.m + b.n)
// works
println(5.total)
println(new A(5).total)
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
case class Container[T](value:T) {
def map[B](f: T => B) = Container(f(value))
}
implicit def ContainerConv[A,B](container:Container[A])
(implicit f: A => B): Container[B] = container.map(f)
val container = Container(1)
container.value.total //Works, as expected
def containerCTotal(containerC: Container[C]) = containerC.value.total
containerCTotal(container) //Works too!
implicit def listConv[A,B](collection: List[A])
(implicit f: A => B): List[B] = collection.map(f)
val list = List(1)
def CTotals(list: List[C]) = list.map(_.total)
CTotals(listConv(list)) //Explicit conversion works, finds the chain implicit conversions Int => C :)
CTotals(list) //... but implicit does not :(
def ATotals(list: List[A]) = list.map(_.total)
ATotals(list) // Simple (non-chained) conversion of contained values does not work either :(
}
How can I make these last conversions work?
I also tried the (deprecated) view bounds, getting the same results:
implicit def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
Just in case, the compilation error is the expected:
type mismatch;
found : List[Int]
required: List[ChainImplicits.C]
CTotals(list) //... but implicit does not :(
And similarly for ATotals(list)
I tried it on scala versions 2.11.8 and 2.11.4.
UPDATE:
I confirmed after Andreas' comment that the underlying issue has something to do with the List being covariant. Giving covariance to the Container class above (i.e. Container[+A]) makes the previously working implicit conversion at containerCTotal(container) to fail.