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

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()

Related

Shapeless - Generic Repr Type manipulation

If I have a method such as:
def f[T: Generic, U: Generic](t: T): U
Generic[T].to(t) returns type Generic[T]#Repr which I assume is a type alias for some type of HList.
Is it possible to select members from the HList and build another HList which I can convince the compiler is of type Generic[U]#Repr which I can then use to create an instance of U using Generic[U].from(myNewHList)?
I have tried many approaches but seem to be going around in circles.
When doing stuff like this in Shapeless, the best place to look is in the shapeless.ops typeclasses. In this case, since you know your second class is a strict subset of your first, Intersection is sufficient to get what you want. You'll want to set this up as a type class, so that you can pass in your input and output types and let the compiler infer the intermediate stuff.
trait Converter[A,B] {
def convert(a: A): B
}
object Converter {
def apply[A,B](implicit converter: Converter[A,B]) = converter
implicit def genericConverter[A, B, ARepr <: HList, BRepr <: HList](
implicit
genA: Generic.Aux[A,ARepr],
genB: Generic.Aux[B,BRepr],
intersection: shapeless.ops.hlist.Intersection.Aux[ARepr,BRepr,BRepr]
): Converter[A,B] =
new Converter[A,B]{def convert(a: A): B = genB.from(intersection(genA.to(a)))}
}
This can be used as follows:
case class Foo(a: Int, b: Int, c: String)
case class Bar(a: Int, c: String)
val foo = Foo(1,2,"Three")
val bar: Bar = Converter[Foo, Bar].convert(foo)

Higher order type classes in scala

I am trying to understand typeclasses and so far i got to Monoids, which are simple enough:
object AbstractAlgebra {
case class Pair[A,B](a: A, b: B)
trait Monoid[T] {
def times(t1: T, t2: T): T
def unit: T
}
object Monoid {
implicit object MonoidIntPlus extends Monoid[Int] {
def times(i1: Int, i2: Int) = i1 + i2
def unit = 0
}
implicit object StringMonoid extends Monoid[String] {
def times(s1: String, s2: String) = s1 + s2
def unit = ""
}
implicit object PairOfMonoids extends Monoid[Pair[Monoid, Monoid]] = ???
}
}
I suppose my problem is the type Monoid[Pair[Monoid, Monoid]], cause I'm not really dealing with two monoid instances, only two classes that are implicit monoids, but I am not sure how to express that.
Any help or references would be appreciated
Monoid is not a type in itself. It's a type constructor, so Pair[Monoid, Monoid] makes no sense.
What you really want is actually the following: assuming that you have a Monoid type class instance for two given types A and B, then make an instance also for Pair[A, B].
This can be written as follows (the implementation is the most natural one you can derive):
implicit def monoidPair[A, B](implicit A: Monoid[A], B: Monoid[B]): Monoid[Pair[A, B]] = new Monoid[Pair[A, B]] {
def times(p1: Pair[A, B], p2: Pair[A, B]) =
Pair(A.times(p1.a, p2.a), B.times(p1.b, p2.b))
def unit = Pair(A.unit, B.unit)
}
This will do exactly what I explained before: If implicit instances for types Monoid[A] and Monoid[B] are found, then it puts a new implicit instance of type Monoid[Pair[A, B]] in scope.
Note. Your case class Pair[A, B] is already defined in Predef (although it's been deprecated since 2.11.0) as Tuple2[A, B] or (A, B).
Other note. If you don't like defining implicit instances as def or val, you can do the same with an implicit class:
implicit class MonoidPair[A, B](implicit A: Monoid[A], B: Monoid[B]) extends Monoid[Pair[A, B]] {
... //same body as before
}

How to define a method that takes a heterogeneous sequence of objects of types belonging to a certain typeclass?

There is a type that can be parametrized by a certain restricted set of types:
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
Now, I can define a function that takes a collection of a specific type and processes it:
def consume[T : Base](xs: Seq[T]) =
xs.map(x => implicitly[Base[T]].f(x).mkString("-"))
How do I define a function that takes a sequence of objects for types of which there exists an implicit conversion to Base and do the same? In a type-safe way, of course.
If I was not entirely clear, here's what I'd like to have:
consume(Seq(1,"asd", 3)) // => Seq("1-1-1", "a-s-d", "3-3-3")
I'm sure I can achieve it with shapeless' HList, but what about core Scala? Anyway, putting shapeless tag in case functionally inclined guys are willing to help.
import shapeless._
import ops.hlist.Mapper
import ops.hlist.ToList
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
object base extends Poly1 {
implicit def forBase[A : Base] = at[A](x => implicitly[Base[A]].f(x))
}
def consume[T <: HList, Inter <: HList](xs: T)
(implicit
mapBase: Mapper.Aux[base.type, T, Inter],
interToList: ToList[Inter, List[Any]]): Seq[String] = {
xs.map(base).toList.map(_.mkString("-"))
}
Two key parts:
object base extends Poly1 : This is a polymorphic function only defined on types with a Base typeclass instance. It calls Base.f on its arg.
The implicits and type params in consume :
T is our input HList type. Inter is an intermediate type variable that is the output type of the result of mapping base over T.
mapBase: Mapper.Aux[base.type, T, Inter] : This is evidence that if we map base over T we get Inter. We need this to call .map on the incoming hlist. By putting it in our implicits list, we just require that it exists when the function is called. Shapeless will generate this for us if it can. If it can't, it most likely means that you forgot to define a Base instance for a type in T
interToList: ToList[Inter, List[Any]] : This is evidence that you can convert the HList Inter to a List[List[Any]]. So List[Any] must be the least-upperbound type of all the types in Inter. Once again, by putting it in the input implicits, we just require that shapeless can generate this for us. This is just boilerplate to prove to the compiler that we can call toList and get a List[List[Any]]. I haven't found a way to avoid this and the Inter variable in my experiences sadly.
Now thanks to all those implicits, we just call xs.map(base) to get an HList out with the appropriate Base.f applied. Then we call .toList to get a List[List[Any]]. Then we map over those List[Any]s and mkString with dashes as you wanted. And out comes our Seq[String]!
Here is it working in the REPL:
scala> consume(1 :: "asd" :: 3 :: HNil)
res0: Seq[String] = List(1-1-1, a-s-d, 3-3-3)
Here is dirty hack for consume method. Not super type safe and nice but may be fine as a workaround.
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
case class Consumable[T](v: T, base: Base[T])
implicit def toConsumable[T](v: T)(implicit base: Base[T], ev: ClassTag[T]) =
Consumable(v, base)
def consume(xs: Consumable[_]*) =
xs.map(x => x.base.asInstanceOf[Base[Any]].f(x.v).mkString("-"))
println(consume(1, 2, 3))
println(consume("a", "b", "c"))
println(consume(1, 2, "a", "b", "c"))

Adding a `to[Col[_]]` method for a covariant collection

I am implementing a data structure. While it doesn't directly mix in any of Scala's standard collection traits, I want to include the to[Col[_]] method which, given a builder factory, can generate standard Scala collections.
Now assume this, copied from GenTraversableOnce:
trait Foo[+A] {
def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, A, Col[A]]): Col[A]
}
This fails with error: covariant type A occurs in invariant position.
So how can GenTraversableOnce achieve this? I can see in the source code, that they add an annotation.unchecked.uncheckedVariance...
That looks like a dirty trick. If the typer rejects this normally, how can this be safe and switched off with uncheckedVariance?
Variance checking is a very important part of type checking and skipping it may easily cause a runtime type error. Here I can demonstrate a type populated with an invalid runtime value by printing it. I've not been able to make it crash with an type cast exception yet though.
import collection.generic.CanBuildFrom
import collection.mutable.Builder
import scala.annotation.unchecked.uncheckedVariance
trait Foo[+A] {
def toCol[Col[_]](implicit cbf: CanBuildFrom[Nothing, A, Col[A #uncheckedVariance]]): Col[A #uncheckedVariance]
}
object NoStrings extends Foo[String] {
override def toCol[Col[_]](implicit cbf: CanBuildFrom[Nothing, String, Col[String]]): Col[String] = {
val res : Col[String] = cbf().result
println("Printing a Col[String]: ")
println(res)
res
}
}
case class ExactlyOne[T](t : T)
implicit def buildExactlyOne = new CanBuildFrom[Nothing, Any, ExactlyOne[Any]] {
def apply() = new Builder[Any, ExactlyOne[Any]] {
def result = ExactlyOne({})
def clear = {}
def +=(x : Any) = this
}
def apply(n : Nothing) = n
}
val noStrings : Foo[Any] = NoStrings
noStrings.toCol[ExactlyOne]
Here println(res) with res : Col[String] prints ExactlyOne(()). However, ExactlyOne(()) does not have a type of Col[String], demonstrating a type error.
To solve the problem while respecting variance rules we can move the invariant code out of the trait and only keep covariant part, while using implicit conversion to convert from covariant trait to invariant helper class:
import collection.generic.CanBuildFrom
trait Foo[+A] {
def to[R](implicit cbf: CanBuildFrom[Nothing, A, R]): R
}
class EnrichedFoo[A](foo : Foo[A]) {
def toCol[Col[_]](implicit cbf: CanBuildFrom[Nothing, A, Col[A]]): Col[A] =
foo.to[Col[A]]
}
implicit def enrich[A](foo : Foo[A]) = new EnrichedFoo(foo)
case class Bar[A](elem: A) extends Foo[A] {
def to[R](implicit cbf: CanBuildFrom[Nothing, A, R]): R = {
val b = cbf()
b += elem
b.result()
}
}
val bar1 = Bar(3)
println(bar1.toCol[Vector])
It can because it is using the #uncheckedVariance annotation to circumpass the type system and ignore variance checking.
Simply import scala.annotation.unchecked.uncheckedVariance and annotate the type for which you want the variance checking disabled:
def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, A, Col[A #uncheckedVariance]]): Col[A #uncheckedVariance]
See a more complete explanation in the related answer.
I read the link to the other question mentioned by #axel22. It still doesn't appear to be the actual reason, though (allowing GenTraversableOnce to function both for variant and invariant collections—it is covariant in A).
For example, the following works correctly without coercing the typer:
import collection.generic.CanBuildFrom
trait Foo[+A] {
def to[A1 >: A, Col[_]](implicit cbf: CanBuildFrom[Nothing, A1, Col[A1]]): Col[A1]
}
case class Bar[A](elem: A) extends Foo[A] {
def to[A1 >: A, Col[_]](implicit cbf: CanBuildFrom[Nothing, A1, Col[A1]]): Col[A1]= {
val b = cbf()
b += elem
b.result()
}
}
This would in my opinion be the correct signature. But then of course, it gets ugly:
val b = Bar(33)
b.to[Int, Vector]
So, my interpretation of the use of #uncheckedVariance is merely to avoid having to repeat the element type (as upper bound) in the to signature.
That still doesn't answer, though, if we can imagine a case which results in a runtime error from neglecting the variance?

Adding a pairwise difference to generic collections - implicit resolution doesn't kick in

Ok, so I have this:
implicit final class RichIterableLike[A, Repr <: IterableLike[A, Repr]](val it: Repr)
extends AnyVal {
def pairDiff[To](implicit num: Numeric[A], cbf: CanBuildFrom[Repr, A, To]): To = {
val b = cbf(it)
val iter = it.iterator
if (iter.hasNext) {
var pred = iter.next()
while (iter.hasNext) {
import num.mkNumericOps
val succ = iter.next()
b += succ - pred
pred = succ
}
}
b.result()
}
}
This compiles, but doesn't kick in:
val stabs = IndexedSeq(1.0, 2.0, 3.0)
stabs.pairDiff
Gives: value pairDiff is not a member of IndexedSeq[Double]
Explicit conversion works:
new RichIterableLike[Double, IndexedSeq[Double]](stabs).pairDiff
... how to fix this?
EDIT
If I apply the approach of this answer, it works:
implicit final class RichIterableLike[A, CC[~] <: Iterable[~]](val it: CC[A])
extends AnyVal {
def pairDiff[To](implicit num: Numeric[A], cbf: CanBuildFrom[CC[A], A, To]): To = {
...
}
But the question remains, what is the crucial difference that makes the implicit lookup kick in in the latter case.
In order for the implicit lookup to work it needs a link between A and Repr (IterableLike demands that link). You pass it in as an argument, so that argument should be typed as Repr[A]. That means you need to modify your signature so it will look something like this:
RichIterableLike[A, Repr[X] <: IterableLike[X, Repr[X]]](val it: Repr[A])
With the above signature you say:
I have an object that accepts a type parameter, I will name that object Repr and when you pass it in I would like to capture the type parameter as well. I will name that type parameter A. As an extra condition I want the type of Repr to conform to the signature of IterableLike