CanBuildFrom and upper type bound parameters - scala

Here is a minimalistic example:
def map[U[_] <: Traversable[T], T](col: U[T]): U[T]
= col.map(identity)
This code does not compile.
type mismatch;
found : Traversable[T]
required: U[T]
= col.map(identity)
My understanding of the problem is the col.map(identity) where the compiler infers an implicit CanBuildFrom[U[T], T, Traversable[T]] instead of desired CanBuildFrom[U[T], T, U[T]].
Is there a way to make this code working?

The mechanics of builder type classes in Scala 2.12 is something like so
def foo[CC[x] <: Traversable[x], A, B](as: CC[A], f: A => B)(
implicit cbf: CanBuildFrom[CC[A], B, CC[B]]
): CC[B] = {
val bf = cbf()
as.foreach { a => bf += f(a) }
bf.result()
}
or using .to method
def foo[CC[x] <: Traversable[x], A, B](as: CC[A], f: A => B)(
implicit cbf: CanBuildFrom[CC[A], B, CC[B]]
): CC[B] = {
as.map(f).to[CC]
}
Corresponding Scala 2.13 code might be
def foo[CC[x] <: Iterable[x], A, B](as: CC[A], f: A => B)(
implicit cbf: BuildFrom[CC[A], B, CC[B]]
): CC[B] = {
cbf.fromSpecific(as)(as.map(f))
}
or using factory
def foo[CC[x] <: Iterable[x], A, B](as: CC[A], f: A => B)(
implicit factory: Factory[B, CC[B]]
): CC[B] = {
as.map(f).to(factory) // equivalent to factory.fromSpecific(as.map(f))
}
The meanings of three type parameters of collection builder type class are
| source coll | element of target coll | target coll |
---------------------------------------------------------------------
CanBuildFrom | -From | -Elem | +To |
BuildFrom | -From | -A | +C |
Factory | | -A | +C |
Note these builder type classes are just generalised version of the following idea
scala> val bf = List.newBuilder[Int]
val bf: scala.collection.mutable.Builder[Int,List[Int]] = ListBuffer()
scala> bf += 1 += 4
val res0: bf.type = ListBuffer(1, 4)
scala> bf.result()
val res1: List[Int] = List(1, 4)
but in practice we rarely see collections constructed in such way.
Another option instead of BuildFrom is to use cats type classes such as Functor.

Related

Why eta-expansion of polymorphic method does not result in polymorphic function value?

Scala 2 does not have polymorphic function values so eta-expanding polymorphic methods gives only
scala> def f[A](a: A): A = ???
def f[A](a: A): A
scala> f _
val res0: Nothing => Nothing = $Lambda$7757/1502613782#45af2c1
However Scala 3 does have polymorphic function values so why eta-expanding polymorphic methods does not give more than
scala> def f[A](a: A): A = ???
def f[A](a: A): A
scala> f
val res0: Any => Any = Lambda$7538/1430563609#4a905603
scala> val g: ([A] => A => A) = f
1 |val g: ([A] => A => A) = f
| ^
| Found: Any => Any
| Required: PolyFunction{apply: [A](x$1: A): A}

Covariance between 3 types in Scala

I'm trying to see if there is a way to find a type W2 that is the super type of 2 types W and E.
In my solution E represents errors, and W represents Warnings.
What I'm trying to accomplish is a method or that if this fails runs that and moves the error to the warning type.
Here is a simplified example of what I'm doing.
sealed trait Validator[-I, +E, +W, +A] extends Product with Serializable
this type has several cases, which aren't really important here, so instead I'll go over an example usage:
case class MyObj(coords: GeoCoords)
case class GeoCoords(lat: String, long: String)
// Getters
val getLatitude: Validator[GeoCoords, Nothing, Nothing, String] = from[GeoCoords].map(_.lat)
val getLongitude: Validator[GeoCoords, Nothing, Nothing, String] = from[GeoCoords].map(_.long)
val parseLatitude: Validator[GeoCoords, Exception, Nothing, Double] = getLatitude andThen nonEmptyString andThen convertToDouble
val parseLongitude: Validator[GeoCoords, Exception, Nothing, Double] = getLongitude andThen convertToDouble
Now this is a bad example, but what I'm looking to do is that because parseLatitude has an error type of Exception, perhaps I want to give a default instead, but still understand that it failed. I'd like to move the Exception from the E error param to the W warning param like this:
val defaultLatitude: Validator[GeoCoords, Nothing, Nothing, Double] = success(0)
val finalLatitude: Validator[GeoCoords, Nothing, Exception, Double] = parseLatitude or defaultLatitude
But as well, if instead of supplying default, the other action I take after the or may fail as well, therefore this should also be the case:
val otherAction: Validator[GeoCoords, Throwable, Nothing, Double] = ???
val finalLatitude: Validator[GeoCoords, Throwable, Exception, Double] = parseLatitude or otherAction
I've tried implementing or in several ways on the Validator type but everytime it gives me an issue, basically casting things all the way up to Any.
def or[I2 <: I, E2 >: E, W2 >: W, B >: A](that: Validator[I2, E2, W2, B]): Validator[I2, E2, W2, B] = Validator.conversion { (i: I2) =>
val aVal: Validator[Any, E, W, A] = this.run(i)
val bVal: Validator[Any, E2, W2, B] = that.run(i)
val a: Vector[W2] = aVal.warnings ++ bVal.warnings
// PROBLEM HERE
val b: Vector[Any] = a ++ aVal.errors
Result(
aVal.warnings ++ aVal.errors ++ bVal.warnings,
bVal.value.toRight(bVal.errors)
)
}
I need to be able to say that W2 is both a supertype of W and of E so that I can concatenate the Vectors together and get type W2 at the end.
A super simplified self contained example is:
case class Example[+A, +B](a: List[A], b: List[B]) {
def or[A2 >: A, B2 >: B](that: Example[A2, B2]): Example[A2, Any] = {
Example(that.a, this.a ++ this.b ++ that.a)
}
}
object stackoverflow extends App {
val example1 = Example(List(1, 2), List(3, 4))
val example2 = Example(List(5, 6), List(7, 8))
val example3 = example1 or example2
}
Where I want the output type of or to be Example[A2, B2] instead of Example[A2, Any]
Actually you want the concatenation of a List[A] and a List[B] to produce a List[A | B], where A | B is union type.
How to define "type disjunction" (union types)?
In Scala 2 union types are absent but we can emulate them with type classes.
So regarding "super simplified example" try a type class LUB (least upper bound)
case class Example[A, B](a: List[A], b: List[B]) {
def or[A2 >: A, B2, AB](that: Example[A2, B2])(
implicit
lub: LUB.Aux[A, B, AB],
lub1: LUB[AB, A2]
): Example[A2, lub1.Out] = {
Example(that.a, (this.a.map(lub.coerce1) ++ this.b.map(lub.coerce2)).map(lub1.coerce1(_)) ++ that.a.map(lub1.coerce2(_)))
}
}
val example1: Example[Int, Int] = Example(List(1, 2), List(3, 4))
val example2: Example[Int, Int] = Example(List(5, 6), List(7, 8))
val example3 = example1 or example2
// example3: Example[Int, Any] // doesn't compile
example3: Example[Int, Int] // compiles
trait LUB[A, B] {
type Out
def coerce1(a: A): Out
def coerce2(b: B): Out
}
trait LowPriorityLUB {
type Aux[A, B, Out0] = LUB[A, B] { type Out = Out0 }
def instance[A, B, Out0](f: (A => Out0, B => Out0)): Aux[A, B, Out0] = new LUB[A, B] {
override type Out = Out0
override def coerce1(a: A): Out0 = f._1(a)
override def coerce2(b: B): Out0 = f._2(b)
}
implicit def bSubtypeA[A, B <: A]: Aux[A, B, A] = instance(identity, identity)
}
object LUB extends LowPriorityLUB {
implicit def aSubtypeB[A <: B, B]: Aux[A, B, B] = instance(identity, identity)
implicit def default[A, B](implicit ev: A <:!< B, ev1: B <:!< A): Aux[A, B, Any] =
instance(identity, identity)
}
// Testing:
implicitly[LUB.Aux[Int, AnyVal, AnyVal]]
implicitly[LUB.Aux[AnyVal, Int, AnyVal]]
implicitly[LUB.Aux[Int, String, Any]]
implicitly[LUB.Aux[Int, Int, Int]]
// implicitly[LUB.Aux[Int, AnyVal, Any]] // doesn't compile
<:!< is from here:
Scala: Enforcing A is not a subtype of B
https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/package.scala#L48-L52
If you want Example to be covariant
case class Example[+A, +B]...
make LUB and LUB.Aux contravariant
trait LUB[-A, -B]...
type Aux[-A, -B, Out0] = LUB[A, B] { type Out = Out0 }

Scala: abstracting over a path-dependent type in impilicit parameter

Let's say I have a class:
abstract class NumericCombine[A:Numeric,B:Numeric]{
type AB <: AnyVal
}
I want to define a function that returns a value of type NumericCombine[A,B].AB. for instance:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB
but the compiler doesn't let me reference .AB in plus.
FYI, this is the context of this question.
I want to provide:
implicit object IntFloat extends NumericCombine[Int,Float]{override type AB = Float}
implicit object FloatInt extends NumericCombine[Float,Int]{override type AB = Float}
and its other 44 friends (7*6-2) so that I can define my plus as below:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB =
{
type AB = Numeric[NumericCombine[A,B].AB]
implicitly[AB].plus(x.asInstanceOf[AB],y.asInstanceOf[AB])
}
plus(1f,2)//=3f
plus(1,2f)//=3f
I am aware of the fact that value conversions in Scala allows me to define
def plus[T](a: T, b: T)(implicit ev:Numeric[T]): T = ev.plus(a,b)
and achieve the behaviour above as suggested here, but since I want to use this function as part of a bigger function (which is described in the link mentioned as the context of this question), I need to parametrize the function with both A and B.
Update:
I made some good progress with this.
My NumericCombine now looks like this:
abstract class NumericCombine[A: Numeric, B: Numeric] {
type AB <: AnyVal
def fromA(x: A): AB
def fromB(y: B): AB
val numeric: Numeric[AB]
def plus(x: A, y: B): AB = numeric.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = numeric.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = numeric.times(fromA(x), fromB(y))
}
and My plus function looks like:
def plus[A: Numeric, B: Numeric](x: A, y: B)(implicit ev:NumericCombine[A,B])
: ev.AB = ev.plus(x, y)
The weighted average function requiring plus ended up becoming a bit more complicated:
def accumulateWeightedValue[A: Numeric,B: Numeric]
(accum: (A, NumericCombine[A, B]#AB), ValueWithWeight: (A, B))
(implicit combine: NumericCombine[A, B], timesNumeric: Numeric[NumericCombine[A, B]#AB])
:(A,NumericCombine[A, B]#AB)=
this is a function that takes (A,AB),(A,B) and returns (A,AB). I use it internally inside weightedSum which just aggregates over this:
def weightedSum[A: Numeric,B: Numeric](weightedValues: GenTraversable[(A, B)])
(implicit numericCombine: NumericCombine[A, B], plusNumeric: Numeric[NumericCombine[A, B]#AB])
: (A, NumericCombine[A, B]#AB)
Now, this compiles fine. It does seem to have a problem with the second implicit parameter. ie Numeric[AB] when I run it with implicit values for say NumericCombine[Int,Float] present. It gives me:
could not find implicit value for parameter plusNumeric:
Numeric[NumericCombine[Int,Float]#AB]
note that in NumericCombine, I have a Numeric[AB] which should be available for implicit look-up. storing it locally, in the case of [Int,Float]:
val lst: Seq[(Int, Float)] =List((1,3f),(1,4f))
implicit val num: Numeric[Float] = IntFloat.numeric //IntFloat extends NumericCombine[Int,Float]
weightedSum(lst)
in a local variable before invoking the function needing it doesn't seem to have any impact. So why is it being picked up by the implicit system.
Just use
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B]#AB
Note the # (hash) instead of . (dot). This is called "type projection". Dot notation is called "path dependent type". I'm telling you these names so that you can google for more info easily. Simply put, # is used for accessing types from classes/traits, and . is used for accessing types from objects/values.
Example:
trait Foo {
type T
}
val fooObj: Foo = new Foo {
type T = Int
}
type t1 = fooObj.T
type t2 = Foo#T
* 18 Apr 2017: updated base on the latest code from author *
* 19 Apr 2017 *
Add NumericCombine#Implicits for convinence
Remove AnyVal constraints to support any Numeric types e.g. BigInt
Refactor NumericCombine
You need Aux pattern:
import scala.collection.GenSeq
trait NumericCombine[A, B] {
type AB
def fromA(x: A): AB
def fromB(y: B): AB
val numericA: Numeric[A]
val numericB: Numeric[B]
val numericAB: Numeric[AB]
// For convenience, caller can 'import combine.Implicits._'
// to bring the Numeric's into the current scope
object Implicits {
implicit def implicitNumericA = numericA
implicit def implicitNumericB = numericB
implicit def implicitNumericAB = numericAB
}
def plus(x: A, y: B): AB = numericAB.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = numericAB.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = numericAB.times(fromA(x), fromB(y))
}
object NumericCombine {
type Aux[A, B, _AB] = NumericCombine[A, B] {
type AB = _AB
}
private def combine[A, B, _AB](fa: A => _AB, fb: B => _AB)
(implicit
_numericA: Numeric[A],
_numericB: Numeric[B],
_numericAB: Numeric[_AB]
): NumericCombine[A, B] = new NumericCombine[A, B] {
override type AB = _AB
override def fromA(x: A): AB = fa(x)
override def fromB(y: B): AB = fb(y)
override val numericA: Numeric[A] = _numericA
override val numericB: Numeric[B] = _numericB
override val numericAB: Numeric[AB] = _numericAB
}
implicit lazy val IntFloat = combine[Int, Float, Float](_.toFloat, identity)
implicit lazy val BigIntBigDecimal = combine[BigInt, BigDecimal, BigDecimal](i => BigDecimal(i), identity)
}
implicit class ValuesWithWeight[A, B](val weightedValue: (A, B)) {
def weight: A = weightedValue._1
def value: B = weightedValue._2
}
def weightedSum[A, B, AB]
(valuesWithWeight: GenSeq[(A, B)])
(implicit combine: NumericCombine.Aux[A, B, AB]):
(A, AB) = {
import combine.Implicits._
val z: (A, AB) =
(combine.numericA.zero, combine.numericAB.zero)
def accumulateWeightedValue(accum: (A, AB), valueWithWeight: (A, B)): (A, AB) = {
val weightedValue = combine.times(valueWithWeight.weight, valueWithWeight.value)
(
combine.numericA.plus(accum.weight, valueWithWeight.weight),
combine.numericAB.plus(accum.value, weightedValue)
)
}
valuesWithWeight.aggregate(z)(
accumulateWeightedValue,
// dataOps.tuple2.plus[A,AB]
{
case ((a1, ab1), (a2, ab2)) =>
(combine.numericA.plus(a1, a2) ->
combine.numericAB.plus(ab1, ab2))
}
)
}
weightedSum(Seq(1 -> 1.5f, 2 -> 1f, 3 -> 1.7f))
weightedSum(Seq(BigInt(1) -> BigDecimal("1.5"), BigInt(2) -> BigDecimal("1"), BigInt(3) -> BigDecimal("1.7")))
An alternative to #slouc's answer is
def plus[A, B](x: A, y: B)(implicit ev: NumericCombine[A, B]): ev.AB
I'd also enhance NumericCombine:
trait NumericCombine[A, B] {
type AB <: AnyVal
def fromA(a: A): AB
def fromB(b: B): AB
val num: Numeric[AB]
}
abstract class NumericCombineImpl[A, B, R](implicit val num: Numeric[R], f1: A => R, f2: B => R) {
type AB = R
def fromA(a: A) = f1(a)
def fromB(b: B) = f2(b)
}
implicit object IntFloat extends NumericCombineImpl[Int,Float,Float]
...
This would allow to actually implement plus, no casts required:
def plus[A, B](x: A, y: B)(implicit ev: NumericCombine[A, B]): ev.AB =
ev.num.plus(ev.fromA(x), ev.fromB(y))

Scala: Triple Context Bounds, evidence parameters not found

I have edited this to a simpler form of the question to which #Zhi Yuan Wang responded :
object ContBound {
def f2[A: Seq, B: Seq]: Unit = {
val a1: Seq[A] = evidence$1
val b2: Seq[B] = evidence$2
}
def f3[A: Seq, B: Seq, C: Seq]: Unit = {
val a1: Seq[A] = evidence$1
val b2: Seq[B] = evidence$2
val a3: Seq[C] = evidence$3
}
}
I get the following errors:
not found value evidence$1
not found value evidence$2
type mismatch; found :Seq[A] required: Seq[C]
despite getting the following in the REPL:
def f3[A: Seq, B: Seq, C: Seq]: Unit =
| {
| val a1: Seq[A] = evidence$1
| val b2: Seq[B] = evidence$2
| val a3: Seq[C] = evidence$3
| }
f3: [A, B, C](implicit evidence$1: Seq[A], implicit evidence$2: Seq[B], implicit evidence$3: Seq[C])Unit
Zhi's awnser is correct. The following compiles:
object ContBound {
def f2[A: Seq, B: Seq]: Unit = {
val a1: Seq[A] = evidence$1
val b2: Seq[B] = evidence$2
}
def f3[A: Seq, B: Seq, C: Seq]: Unit = {
val a1: Seq[A] = evidence$3
val b2: Seq[B] = evidence$4
val a3: Seq[C] = evidence$5
}
}
However I still don't see this as correct behaviour, as these are parameters for two different methods and methods are normally allowed to reuse parameter names.
Have you tried
def comma3[A: RParse, B: RParse, C: RParse, D](f: (A, B, C) => D): D =
expr match {
case CommaExpr(Seq(e1, e2, e3)) =>
f(evidence$3.get(e1), evidence$4.get(e2), evidence$5.get(e3))
}
since the the evidence$1 already used by
def comma3[]??

Iso macro in Scala

If I want to implicitly convert two objects from one to another, is there anyway to do this using something like an Iso macro?
For example, if I have this:
implicit def listToMap[A, B](l: List[(A, B)]): Map[A, B] = l.toMap
implicit def mapToList[A, B](m: Map[A, B]): List[(A, B)] = m.toList
I want to simply write:
implicit def[A, B] listMapIso = Iso[List[(A, B)], Map[A, B]] {_.toMap, _.toList}
Note: As noted below, I plan to use this in my web framework where I convert my database models to middleware/front-end models.
You seem to be confusing several different concepts. Iso, implicit conversions, and macros are all quite different from each other.
We can certainly define an equivalent of Iso for parameterized types, though the syntax becomes a little more cumbersome:
import scalaz._, Scalaz._
case class BiIso[F[_, _], G[_, _]](left: F ~~> G,
right: G ~~> F)
type PairList[A, B] = List[(A, B)]
val listToMap = new (PairList ~~> Map) {
def apply[A, B](l: PairList[A, B]) = l.toMap
}
val mapToList = new (Map ~~> PairList) {
def apply[A, B](m: Map[A, B]) = m.toList
}
val listMapIso = BiIso(listToMap, mapToList)
We can of course make parts of this implicit, though this is an orthogonal concern. We can build the BiIso implicitly:
implicit val listToMap = new (PairList ~~> Map) {
def apply[A, B](l: PairList[A, B]) = l.toMap
}
implicit val mapToList = new (Map ~~> PairList) {
def apply[A, B](m: Map[A, B]) = m.toList
}
implicit def biIso[F[_, _], G[_, _]](implicit left: F ~~> G, right: G ~~> F) =
BiIso(left, right)
implicitly[BiIso[PairList, Map]]
And we can make any BiIso act as an implicit conversion, though I would recommend against it. The only tricky part is guiding the type inference correctly. This is most of the way there, but for some reason the GAB parameter isn't inferred (a correction would be very welcome):
sealed trait BiAny[F[_, _]] {}
object BiAny {
implicit def any[F[_, _]] = new BiAny[F] {}
}
sealed trait ApplyBiIso[FAB, GAB] {
type A1
type B1
type F[_, _]
type G[_, _]
type Required = BiIso[F, G]
val unapplyL: Unapply2[BiAny, FAB] {
type A = A1; type B = B1;
type M[C, D] = F[C, D]
}
val unapplyR: Unapply2[BiAny, GAB] {
type A = A1; type B = B1;
type M[C, D] = G[C, D]
}
def liftBI(bi: Required): Iso[FAB, GAB] =
Iso({ fab: FAB =>
val f: F[A1, B1] = Leibniz.witness(unapplyL.leibniz)(fab)
val g: G[A1, B1] = bi.left(f)
Leibniz.witness(Leibniz.symm[⊥, ⊤, GAB, G[A1, B1]](unapplyR.leibniz))(g): GAB
},
{ gab: GAB =>
val g: G[A1, B1] = Leibniz.witness(unapplyR.leibniz)(gab)
val f: F[A1, B1] = bi.right(g)
Leibniz.witness(Leibniz.symm[⊥, ⊤, FAB, F[A1, B1]](unapplyL.leibniz))(f): FAB
}
)
}
object ApplyBiIso {
implicit def forFG[FAB, A2, B2, GAB, A3, B3](
implicit u1: Unapply2[BiAny, FAB] { type A = A2; type B = B2 },
u2: Unapply2[BiAny, GAB] { type A = A3; type B = B3 }) = new ApplyBiIso[FAB, GAB] {
type A1 = A2
type B1 = B2
type F[C, D] = u1.M[C, D]
type G[C, D] = u2.M[C, D]
//Should do the conversion properly with Leibniz but I can't be bothered
val unapplyL = u1.asInstanceOf[Unapply2[BiAny, FAB] {
type A = A1; type B = B1;
type M[C, D] = F[C, D]
}]
val unapplyR = u2.asInstanceOf[Unapply2[BiAny, GAB] {
type A = A1; type B = B1;
type M[C, D] = G[C, D]
}]
}
type Aux[FAB, GAB, Required1] = ApplyBiIso[FAB, GAB] { type Required = Required1 }
def apply[FAB, GAB](implicit abi: ApplyBiIso[FAB, GAB]): Aux[FAB, GAB, abi.Required] = abi
}
sealed trait AppliedBiIso[FAB, GAB] {
val iso: Iso[FAB, GAB]
}
object AppliedBiIso {
implicit def applyAndIso[FAB, GAB, Required1](
implicit ap: ApplyBiIso.Aux[FAB, GAB, Required1],
iso1: Required1) = new AppliedBiIso[FAB, GAB] {
//Should do the conversion properly with Leibniz but I can't be bothered
val iso = ap.liftBI(iso1.asInstanceOf[BiIso[ap.F, ap.G]])
}
}
implicit def biIsoConvert[FAB, GAB](
f: FAB)(implicit ap: AppliedBiIso[FAB, GAB]): GAB =
ap.iso.left(f)
val map: Map[String, Int] = Map("Hello" -> 4)
val list: PairList[String, Int] =
biIsoConvert[Map[String, Int], PairList[String, Int]](map)
I've no doubt it's possible to make this work correctly.
That still leaves macros, which are again a more or less orthogonal concern. One place I can see they might be relevant is that it's impossible to abstract over kind in scala without using macros. Do you want an equivalent of Iso that works for any "shape", not just F[_, _]? That would be a good use case for a macro - though having written this kind of macro before I don't envy anyone trying to implement it.