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

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

Related

Does shapeless play well with type members?

I'm trying to use shapeless to derive a Generic for a type member defined in a trait, but am not having luck. I have made as simple of a reproduction of the issue as I can think of while keeping it close enough to the original code. I'm taking inspiration from this blog post, and trying to expand (bastardize) it to be a bit more generic. It probably won't make sense why I have code that looks like this from this example alone, but hopefully that doesn't take away from this question :)
I have a trait that declares a type member, a case class representing some common set of fields, and another wrapper case class that combines an instance of both:
object A {
trait TheTrait {
type TheType
}
case class CommonFields(height: Double, isTall: Boolean)
case class Wrapper[T <: TheTrait](commonFields: CommonFields, t: T#TheType)
}
I also have an implementation of the trait:
trait Obj extends TheTrait
object Obj extends Obj {
case class Source(name: String, other: Int)
override type TheType = Source
}
My goal is to be able to take a tuple with values for both CommonFields and TheTrait#TheType for some instance of TheTrait, and to use shapeless to turn that into an instance of a Wrapper. So for the example so far, I'd like to go from something like (5.1, false, "sub", 10) to Wrapper[Obj](CommonFields(5.1, false), Source("other", 10)). Here's what I've come up with:
object Test {
class Constructor[T <: TheTrait] {
// take a tuple of all the fields of CommonFields and T#Trait and produce an instance of each in a A.Wrapper
def apply[In <: Product, All <: HList, ORep <: HList, CRep <: HList, N <: Nat](in: In)(implicit
cGen: Generic.Aux[A.CommonFields, CRep], // generic for CommonFields
cLen: Length.Aux[CRep, N], // the length of the CommonFields generic HList
trGen: Generic.Aux[T#TheType, ORep], // generic for T#TheType
iGen: Generic.Aux[In, All], // generic for input tuple
split: Split.Aux[All, N, CRep, ORep] // the input tuple, split at N, produces HLists for the CommonFields generic rep as well as for the T#TheType generic rep
): A.Wrapper[T] = {
val all = iGen.to(in)
val (cFields, tFields) = split(all)
val com = cGen.from(cFields)
val tr = trGen.from(tFields)
A.Wrapper(com, tr)
}
}
def construct[T <: TheTrait] = new Constructor[T]
println(construct[Obj](5.1, false, "sub", 10))
}
Unfortunately, the correct implicits cannot be found, in particular I see the following error: No implicit arguments of type: hlist.Split.Aux[Double :: Boolean :: String :: Int :: HNil, Succ[Succ[shapeless.nat._0]], Double :: Boolean :: HNil, HNil]
It seems like it is finding the right generic representation for CommonFields (by the appearances of Double :: Boolean :: HNil in the error), but cannot tell what the TheType should be. Is this asking too much of shapeless/the scala compiler? Can I give more type hints somewhere? Is there another way to achieve something like this? I can try to expand on why I have created a type structure like this if that would be helpful. Any ideas are appreciated!
EDIT:
Just to experiment, I made a variation using path dependent typing instead of the type projection, but still was unable to get it to work:
object Test {
import A._
class Constructor[T <: TheTrait] {
// take a tuple of all the fields of CommonFields and T#Trait and produce an instance of each in a A.Wrapper
def apply[In <: Product, All <: HList, ORep <: HList, CRep <: HList, N <: Nat](in: In, t: T /* <=== now takes a `T` instance */)(implicit
cGen: Generic.Aux[CommonFields, CRep], // generic for CommonFields
cLen: Length.Aux[CRep, N], // the length of the CommonFields generic HList
trGen: Generic.Aux[t.TheType, ORep], // generic for T#TheType <==== no more type projection
iGen: Generic.Aux[In, All], // generic for input tuple
split: Split.Aux[All, N, CRep, ORep] // the input tuple, split at N, produces HLists for the CommonFields generic rep as well as for the T#TheType generic
): Wrapper[T] = {
val all = iGen.to(in)
val (cFields, tFields) = split(all)
val com = cGen.from(cFields)
val tr = trGen.from(tFields)
Wrapper(com, tr)
}
}
def construct[T <: TheTrait] = new Constructor[T]
println(
construct[Obj]((5.1, false, "sub", 10), Obj) // <== passing a `TheTrait` instance
)
}
But still seeing the error
No implicit arguments of type: hlist.Split.Aux[Double :: Boolean :: String :: Int :: HNil, Succ[Succ[shapeless.nat._0]], Double :: Boolean :: HNil, HNil]
EDIT 2:
Rearranging the implicits has helped a tad. Instead of the compiler believing that ORep is HNil, it is now at least looking for it to match String :: Int :: HNil:
class Constructor[T <: TheTrait] {
// take a tuple of all the fields of CommonFields and T#Trait and produce an instance of each in a A.Wrapper
def apply[In <: Product, All <: HList, ORep <: HList, CRep <: HList, N <: Nat](in: In, t: T)(implicit
cGen: Generic.Aux[CommonFields, CRep], // generic for CommonFields
cLen: Length.Aux[CRep, N], // the length of the CommonFields generic HList
iGen: Generic.Aux[In, All], // generic for input tuple
split: Split.Aux[All, N, CRep, ORep], // the input tuple, split at N, produces HLists for the CommonFields generic rep as well as for the T#TheType generic
trGen: Generic.Aux[t.TheType, ORep] // generic for T#TheType
): Wrapper[T] = {
val all = iGen.to(in)
val (cFields, tFields) = split(all)
val com = cGen.from(cFields)
val tr = trGen.from(tFields)
Wrapper(com, tr)
}
}
def construct[T <: TheTrait] = new Constructor[T]
The error now is No implicit arguments of type: Generic.Aux[B.Obj.TheType, String :: Int :: HNil], which feels like progress to me.
I can now actually get the program to compile by explicitly creating an instance of the Generic it is looking for and making it available implicitly:
implicit val objTypeGen: Generic.Aux[Obj.TheType, String :: Int :: HNil] = Generic.instance[Obj.TheType, String :: Int :: HNil](
t => t.name :: t.other :: HNil,
{
case n :: o :: HNil => Obj.Source(n, o)
}
)
But now I have removed all of the ergonomics I had originally set out to build. Hopefully there's enough hints here though for someone to figure out how to not need to explicitly pass a TheTrait instance or define the Generic manually?
Your original code compiles as soon as you move override type TheType = Source from object Obj to trait Obj. Note that construct[Obj](..) refers to the type (trait) Obj, not the singleton type corresponding to the object Obj, therefore in your code Obj#TheType cannot be resolved to a particular type, since it remains abstract.
If you really need override type TheType = Source in object Obj, the invocation construct[Obj.type](..) will also compile.
Edit. Full code:
import shapeless.ops.hlist.{Length, Split}
import shapeless.{Generic, HList, Nat}
object Programme {
object A {
trait TheTrait {
type TheType
}
case class CommonFields(height: Double, isTall: Boolean)
case class Wrapper[T <: TheTrait](commonFields: CommonFields, t: T#TheType)
}
import A.TheTrait
trait Obj extends TheTrait {
override type TheType = Obj.Source
}
object Obj extends Obj {
case class Source(name: String, other: Int)
}
object Test {
class Constructor[T <: TheTrait] {
def apply[In <: Product, All <: HList, ORep <: HList, CRep <: HList, N <: Nat](in: In)(implicit
cGen: Generic.Aux[A.CommonFields, CRep],
cLen: Length.Aux[CRep, N],
trGen: Generic.Aux[T#TheType, ORep],
iGen: Generic.Aux[In, All],
split: Split.Aux[All, N, CRep, ORep]
): A.Wrapper[T] = {
val all = iGen.to(in)
val (cFields, tFields) = split(all)
val com = cGen.from(cFields)
val tr = trGen.from(tFields)
A.Wrapper(com, tr)
}
}
def construct[T <: TheTrait] = new Constructor[T]
}
import Test.construct
def main(args: Array[String]): Unit = {
println(construct[Obj](5.1, false, "sub", 10))
}
}

Achieving Ad hoc polymorphism at function parameter level (mixing parameters of different type)

When I have a function in Scala:
def toString[T: Show](xs: T*): String = paths.map(_.show).mkString
And the following type class instances in scope:
implicit val showA: Show[MyTypeA]
implicit val showB: Show[MyTypeB]
I can use function toString in the following ways:
val a1: MyTypeA
val a2: MyTypeA
val stringA = toString(a1, a2)
val b1: MyTypeB
val b2: MyTypeB
val stringB = toString(b1, b2)
But I cannot call toString mixing parameters of type MyTypeA and MyTypeB:
// doesn't compile, T is inferred to be of type Any
toString(a1, b1)
Is it possible to redefine toString in such a way that it becomes possible to mix parameters of different types (but only for which a Show typeclass is available)?
Note that I am aware of the cats show interpolator which solves this specific example, but I'm looking for a solution which can be applied to different cases as well (e.g. toNumber).
I am also aware of circumventing the problem by calling .show on the parameters before passing them to the toString function, but I'm looking for a way to avoid this as it results in code duplication.
Example with shapeless:
object myToString extends ProductArgs { //ProductArgs allows changing variable number of arguments to HList
//polymorphic function to iterate over values of HList and change to a string using Show instances
object showMapper extends Poly1 {
implicit def caseShow[V](implicit show: Show[V]): Case.Aux[V, String] = {
at[V](v => show.show(v))
}
}
def applyProduct[ARepr <: HList](
l: ARepr
)(
implicit mapper: Mapper[showMapper.type, ARepr]
): String = l.map(showMapper).mkString("", "", "")
}
Now let's test it:
case class Test1(value: String)
case class Test2(value: String)
case class Test3(value: String)
implicit val show1: Show[Test1] = Show.show(_.value)
implicit val show2: Show[Test2] = Show.show(_.value)
println(myToString(Test1("a"), Test2("b"))) //"ab"
println(myToString(Test1("a"), Test2("b"), Test3("c"))) //won't compile since there's no instance of Show for Test3
By the way, I think toString is not the best name, because probably it can cause weird conflicts with toString from java.lang.Object.
If you don't want to mess with shapeless, another solution that comes to my mind is to just create functions with different arity:
def toString[A: Show](a: A): String = ???
def toString[A: Show, B: Show](a: A, b: B): String = ???
//etc
It's definitely cumbersome, but it might be the easiest way to solve your problem.
Here's one way to do it in Dotty (note that most of the Dotty-specific features used here are not necessary; they're just to make life easier, but being able to abstract over tuples of different arities is something you can't do (easily) in Scala 2):
opaque type Show[T] = T => String
opaque type ShowTuple[T <: Tuple] = T => String
object ShowTuple {
given ShowTuple[EmptyTuple] = _ => ""
given showTuple[H, T <: Tuple](using show: Show[H], showTail: ShowTuple[T]) as ShowTuple[H *: T] =
{ case h *: t => show(h) + "," + showTail(t) }
}
def multiToString[T <: Tuple](t: T)(using showTuple: ShowTuple[T]) =
showTuple(t)
It can be used like this:
class TypeA(val i: Int)
class TypeB(val s: String)
class TypeC(val b: Boolean)
given Show[TypeA] = t => s"TypeA(${t.i})"
given Show[TypeB] = t => s"TypeB(${t.s})"
given Show[TypeC] = t => s"TypeC(${t.b})"
println(multiToString((new TypeA(10), new TypeB("foo"), new TypeC(true))))
Using a type for which an implicit is not given fails:
class TypeD
multiToString((new TypeA(10), new TypeB("foo"), new TypeC(true), new TypeD))
Try it in Scastie
What is the type of paths?
If it's List[T] then there should be an implicit Show[T] in scope.
If it's List[Any] then there should be an implicit Show[Any] in scope.
If paths contains elements of different types and paths is not a List[Any] then paths shouldn't be a List[...] at all. It can be of type L <: HList. You can try
import shapeless.{HList, HNil, Poly1, Poly2}
import shapeless.ops.hlist.{LeftReducer, Mapper}
trait Show[T] {
def show(t: T): String
}
implicit class ShowOps[T](t: T) {
def show(implicit s: Show[T]): String = s.show(t)
}
object show extends Poly1 {
implicit def cse[T: Show]: Case.Aux[T, String] = at(_.show)
}
object concat extends Poly2 {
implicit def cse: Case.Aux[String, String, String] = at(_ + _)
}
def toString[L <: HList, L1 <: HList](xs: L)(implicit
mapper: Mapper.Aux[show.type, L, L1],
reducer: LeftReducer.Aux[L1, concat.type, String]
): String = xs.map(show).reduceLeft(concat)
type MyTypeA
type MyTypeB
implicit val showA: Show[MyTypeA] = ???
implicit val showB: Show[MyTypeB] = ???
val a1: MyTypeA = ???
val b1: MyTypeB = ???
toString(a1 :: b1 :: HNil)

Understanding Mixed Context Bounds of Seq[AnyVal] and Seq[String]

Suppose I have some function that should take a sequence of Ints or a sequence of Strings.
My attempt:
object Example extends App {
import scala.util.Random
val rand: Random.type = scala.util.Random
// raw data
val x = Seq(1, 2, 3, 4, 5).map(e => e + rand.nextDouble())
val y = Seq("chc", "asas")
def f1[T <: AnyVal](seq: Seq[T]) = {
println(seq(0))
}
// this works fine as expected
f1(x)
// how can i combine
f1(y)
}
How can I add this to also work with strings?
If I change the method signature to:
def f1[T <: AnyVal:String](seq: Seq[T])
But this won't work.
Is there a way to impose my required constraint on the types elegantly?
Note the difference between an upper bound
A <: C
and a context bound
A : C
so type parameter clause [T <: AnyVal : String] does not make much sense. Also types such as String are rarely (or never) used as context bounds.
Here is a typeclass approach
trait EitherStringOrAnyVal[T]
object EitherStringOrAnyVal {
implicit val str: EitherStringOrAnyVal[String] = new EitherStringOrAnyVal[String] {}
implicit def aval[T <: AnyVal]: EitherStringOrAnyVal[T] = new EitherStringOrAnyVal[T] {}
}
def f1[T: EitherStringOrAnyVal](seq: Seq[T]): Unit = {
println(seq(0))
}
f1(Seq(1)) // ok
f1(Seq("a")) // ok
f1(Seq(Seq(1))) // nok
or generelized type constraints approach
object Foo {
private def impl[T](seq: Seq[T]): Unit = {
println(seq(0))
}
def f1[T](seq: Seq[T])(implicit ev: T =:= String): Unit = impl(seq)
def f1[T <: AnyVal](seq: Seq[T]): Unit = impl(seq)
}
import Foo._
f1(Seq(1)) // ok
f1(Seq("a")) // ok
f1(Seq(Seq(1))) // nok
I feel like you should write a separate function for both, but there are other ways to do it:
In Dotty, you can just use union types, which is what I'd recommend here:
Edit: As per Alexey Romanov’s suggestion, replaced Seq[AnyVal | String] with Seq[AnyVal | String], which was wrong,
def foo(seq: Seq[AnyVal] | Seq[String]): Unit = {
println(seq)
}
Scastie
If you're not using Dotty, you can still do this in Scala 2 with a couple reusable implicit defs
class Or[A, B]
implicit def orA[A, B](implicit ev: A): Or[A, B] = new Or
implicit def orB[A, B](implicit ev: B): Or[A, B] = new Or
def foo[T](seq: Seq[T])(implicit ev: Or[T <:< AnyVal, T =:= String]): Unit =
println(seq)
foo(Seq("baz", "waldo"))
foo(Seq(23, 34))
foo(Seq(List(), List())) //This last one fails
Scastie
You can also do it with a typeclass, as Luis Miguel Mejía Suárez suggested, but I wouldn't recommend it for such a trivial task since you still have to define 2 functions for each type, along with a trait, 2 implicit objects, and one function that can use instances of that trait. You probably don't want this pattern to handle just 2 different types.
sealed trait DoSomethingToIntOrString[T] {
def doSomething(t: Seq[T]): Unit
}
implicit object DoSomethingToAnyVal extends DoSomethingToAnyValOrString[AnyVal] {
def doSomething(is: Seq[AnyVal]): Unit = println(is)
}
implicit object DoSomethingToString extends DoSomethingToIntOrString[String] {
def doSomething(ss: Seq[String]): Unit = println(ss)
}
def foo[T](t: Seq[T])(implicit dsis: DoSomethingToIntOrString[T]): Unit = {
dsis.doSomething(t)
}
foo(Seq("foo", "bar"))
foo(Seq(1, 2))
In Scastie
def f1( seq: Seq[Any] ): Unit =
println( seq( 0 ) )
This works, because the least common supertype of Int and String (the 'lowest' type that is a supertype of both) would be Any, since Int is a subtype of AnyVal (i.e. 'the primitives) and String is a subtype of AnyRef (i.e. `the heap objects). f1 does not depends in any way on the contents of the list and is not polymorphic in its return type (Unit), so we don't need a type parameter at all.

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

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?