I cannot make this work:
abstract class AlternativeSortingType[T, B](implicit val ord: scala.math.Ordering[B]) {
def convert(t: T): B
}
case class LengthSortingType() extends AlternativeSortingType[String, Int] {
def convert(t: String): Int = t.length
}
class ProduceResult {
var c: AlternativeSortingType[String, _] = LengthSortingType()
def sort(l: List[String]) = l.sortBy(c.convert(_))(c.ord)
}
It complains with the following:
<console>:20: error: type mismatch;
found : scala.math.Ordering[_$1]
required: scala.math.Ordering[Any]
Note: _$1 <: Any, but trait Ordering is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
def sort(l: List[String]) = l.sortBy(c.convert(_))(c.ord)
^
I already tried to put the type B to the method only, but I don't see how to get rid of the wilcard. I want to be able to sort by specifying any kind of converter.
How to make the type match?
I found a workaround in which I can even now make composition of orderings.
abstract class AlternativeSortingType[T] extends Ordering[T] { self =>
def &&(other: AlternativeSortingType[T]): AlternativeSortingType[T] = new AlternativeSortingType[T] {
def compare(e: T, f: T): Int = {
val ce = self.compare(e, f)
if(ce == 0) other.compare(e, f) else ce
}
}
}
case class LengthSortingType() extends AlternativeSortingType[String] {
def compare(e: String, f: String): Int = e.length - f.length
}
case class DictionarySortingType() extends AlternativeSortingType[String] {
def compare(e: String, f: String): Int = if(e < f) -1 else if(e==f) 0 else 1
}
class ProduceResult {
var c: AlternativeSortingType[String] = LengthSortingType() && DictionarySortingType()
def sort(l: List[String]) = l.sortWith((e,f) => c.compare(e, f) < 0)
}
Related
I am using scala 2.11.
I have question on the scala generic types and pattern matching.
In the class MyImpl.example(), compiler is unhappy saying type mismatch, Required: _$1, Found: X[_ <: A]
trait A
class B extends A
class C extends A
trait Foo[T <: A] {
def foo(arg: T): Unit
}
class Bar extends Foo[B] {
override def foo(arg: B): Unit = print("Bar")
}
class Car extends Foo[C] {
override def foo(arg: C): Unit = print("Car")
}
class MyImpl {
def getA(): A = {
new B()
}
def example(): Unit = {
getFoo("1").foo(getA())
}
def getFoo(something: String): Foo[_ <: A] = {
//return either
something match {
case "1" => new Bar()
case "2" => new Car()
}
}
}
object Test {
def main(args: Array[String]) = {
new MyImpl().example()
}
}
Note: getFoo("1") is more dynaminc in my real case, here is just an example.
I kind of understand this, compiler is unable to predict on which pair of the 2 implementation the method is invoked.
I am able to work around this, if I change the implementation of MyImpl.example() to
def example(): Unit = {
(getFoo("1"), getA()) match {
case (i: Bar, j: B) => i.foo(j)
case (i: Car, j: C) => i.foo(j)
}
}
I am not really happy with this as I am just repeating i.foo(j)
Any scala functional style writing much cleaner code?
Basically you want something like
(getFoo("1"), getA()) match {
case (i: Foo[t], j: t) => i.foo(j) // doesn't compile, not found: type t
}
or
(getFoo("1"), getA()) match {
case (i: Foo[t], j: Id[t]) => i.foo(j) // doesn't compile, t is already defined as type t
}
type Id[T] = T
You can remove code duplication in
def example(): Unit = { // (*)
(getFoo("1"), getA()) match {
case (i: Bar, j: B) => i.foo(j)
case (i: Car, j: C) => i.foo(j)
}
}
(or fix compilation of getFoo("1").foo(getA()))
with nested pattern matching
getFoo("1") match {
case i => getA() match {
case j: i._T => i.foo(j)
}
}
if you add type member _T
trait Foo[T <: A] {
type _T = T
def foo(arg: T): Unit
}
For getFoo("1") and getA producing new B this prints Bar, vice versa for getFoo("2") and new C this prints Car, for other combinations this throws ClassCastException similarly to (*).
Please notice that this can't be rewritten as just a variable declaration and single pattern matching
val i = getFoo("1")
getA() match {
case j: i._T => i.foo(j)
}
//type mismatch;
// found : j.type (with underlying type i._T)
// required: _$1
because for nested pattern matching the types are inferred correctly (i: Foo[t], j: t) but for val i the type is existential (i: Foo[_] aka i: Foo[_$1] after skolemization, j: _$1).
Here is a simplified version of my code.
How can I avoid to call asInstanceOf (because it is a smell for a poorly design solution) ?
sealed trait Location
final case class Single(bucket: String) extends Location
final case class Multi(buckets: Seq[String]) extends Location
#SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
class Log[L <: Location](location: L, path: String) { // I prefer composition over inheritance
// I don't want to pass location to this method because it's a property of the object
// It's a separated function because there is another caller
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths(): Seq[String] =
location match {
case _: Single => Seq(this.asInstanceOf[Log[_ <: Single]].getSinglePath())
case m: Multi => m.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
Try a type class
class Log[L <: Location](location: L, val path: String) {
def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location, this)
}
trait GetPaths[L <: Location] {
def getPaths(location: L, log: Log[L]): Seq[String]
}
object GetPaths {
implicit val single: GetPaths[Single] = (_, log) => Seq(log.getSinglePath())
implicit val multi: GetPaths[Multi] = (m, log) => m.buckets.map(bucket => s"fs://${bucket}/${log.path}")
}
Normally a type class is a compile-time replacement for pattern matching.
I had to make getSinglePath public and path a val in order to provide access to them inside GetPaths. If you don't want to do so you can make the type class nested into Log
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths[L]): Seq[String] = gp.getPaths(location)
private trait GetPaths[L1 <: Location] {
def getPaths(location: L1): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths[L] = _ => Seq(getSinglePath())
implicit val multi: GetPaths[Multi] = _.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
Actually we don't have to pass location explicitly and we don't need L1
class Log[L <: Location](location: L, path: String) {
private def getSinglePath()(implicit ev: L <:< Single): String = s"fs://${location.bucket}/$path"
def getPaths()(implicit gp: GetPaths): Seq[String] = gp.getPaths()
private trait GetPaths {
def getPaths(): Seq[String]
}
private object GetPaths {
implicit def single(implicit ev: L <:< Single): GetPaths = () => Seq(getSinglePath())
implicit def multi(implicit ev: L <:< Multi): GetPaths = () => location.buckets.map(bucket => s"fs://${bucket}/$path")
}
}
Now GetPaths is zero-parameter type class and slightly similar to magnet pattern.
I am facing an error about unreachable implicits in scope:
Error:(38, 68) could not find implicit value for parameter strategy: XXX.NeoStrategy[T]
(summoner: Summoner, v: String) => summoner.summonEvaluation[T](v)
I implement the answer of Tim to that question : https://stackoverflow.com/a/56668734/3896166
I tried to import the implicit object Strategies within TypeTable scope with :
import XXX.NeoStrategies._
but to no success.
The followings are each file of the base logic I want to use:
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
trait NeoStrategy[T <: Type_top] {
def evaluate(v: String, helper: Helper): Int
}
object NeoStrategies {
implicit object NeoStrategy_A extends NeoStrategy[Type_A] {
def evaluate(v: String, helper: Helper): Int = 1
}
implicit object NeoStrategy_B extends NeoStrategy[Type_B] {
def evaluate(v: String, helper: Helper): Int = 2
}
}
case class Helper(name: String) {
def summonEvaluation[T <: Type_top](v: String)(implicit strategy: NeoStrategy[T]): Int = {
strategy.evaluate(v, this)
}
}
trait TypeOMap {
protected def computeStuff[T <: Type_top]: (Helper, String) => Int
protected val computeMap: Map[String, (Helper, String) => Int]
}
import XXX.NeoStrategies._
trait TypeTable extends TypeOMap {
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v)
}
override protected val computeMap = Map(
"a" -> computeStuff[Type_A],
"b" -> computeStuff[Type_B]
)
}
class Summoner extends TypeTable {
def callsMapAndEvaluates(typeIdentifier: String, helper: Helper, param: String): Double = {
computeMap(typeIdentifier)(helper, param)
}
}
object StackO {
def main(args: Array[String]): Unit = {
val mySummoner = new Summoner
// mySummoner allows the selecting of a given type with
// its "typeIdentifier" input in combination with the "TypeTable" it extends
val r = mySummoner.callsMapAndEvaluates("a", Helper("make it right"), "I, parameter")
}
}
This is not the first time I use implicits but not with something like the computeMap above. Still, I understand the logic of it, but fail at making it right.
How can I have summoner.summonEvaluation[T](v) find the required implicit?
Just add context bound
override protected def computeStuff[T <: Type_top : NeoStrategy] ...
It seems you want to work with singleton types. In Scala 2.12 + Shapeless
import shapeless.Witness
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux[Witness.`"a"`.T, Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux[Witness.`"b"`.T, Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String](s: Witness.Aux[S])(implicit
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s.value, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
In Scala 2.13
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String with Singleton] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String with Singleton, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String with Singleton, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux["a", Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux["b", Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String with Singleton](s: S)(implicit
value: ValueOf[S],
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
The underlying problem is this:
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v) // implicit for NeoStrategy[T]...?
}
Since summonEvaluation[T] requires an implicit argument of type NeoStrategy[T], this means you must have one in scope for any T that's a subclass of Type_top. However, NeoStrategies only provides two instances: one for Type_A and Type_B. This is not enough for the compiler. Understandably so - for instance, you haven't provided any NeoStrategy for
Type_top itself
subclasses of Type_A and Type_B (perfectly legal to create)
There are two basic ways you can handle this:
Delaying the implicit resolution
As per the other answer, instead of trying to resolve the implicit inside computeStuff, add a context bound there too. If the point where you have to supply the implicit is only reached when you know what T is, you won't have to provide instances for any possible subtype.
Providing implicits for all possible subtypes
If absolutely you want to keep the implicit resolution inside computeStuff, you're going to have to offer a method
implicit def getNeoStrategy[T <: Type_top] : NeoStrategy[T] = ???
Unfortunately, doing this is probably going to involve a bunch of reflection and potentially runtime errors for edge cases, so I'd recommend the context bound on computeStuff.
I want to write a type class, to add some behavior to a generic type. However, I cannot figure out how to do it; I keep running into the error below.
Imagine you have a generic type MyList[A]:
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
Now you want to add some behavior to this class, e.g. to convert it into a Stream[A]. A type class based extension would seem appropriate:
// inspired by https://scalac.io/typeclasses-in-scala
trait MyListExt[T, A <: MyList[T]] {
def stream(a: A): Stream[T]
}
object MyListExt {
def apply[T, A <: MyList[T]](implicit a: MyListExt[T, A]): MyListExt[T, A] = a
object ops {
implicit class MyListExtOps[T, A <: MyList[T]](val a: A) extends AnyVal {
def stream(implicit ext: MyListExt[T, A]): Stream[T] = ext.stream(a)
}
}
private type T0
implicit val myListToStreamImpl: MyListExt[T0, MyList[T0]] = new MyListExt[T0, MyList[T0]] {
override def stream(a: MyList[T0]): Stream[T0] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
When I now try to use this type class in my code, I get the following error at l.stream:
No implicits found for parameter ext: MyListExt[T_, MyList[Int]]
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
What am I doing wrong, or how can I get my l.stream to work?
I have seen many examples involving type classes and implicit conversion, but none so far operating on generic types.
implicit def myListToStreamImpl[T]: MyListExt[T, MyList[T]] = new MyListExt[T, MyList[T]] {
override def stream(a: MyList[T]): Stream[T] = {
def fold(l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty[T1])
}
}
Your types don't align because you've used that private type for whatever bizarre reason. Types nested inside objects have a completely different application, and they don't relate to your current use case.
The trouble is that in l.stream.foreach(println) the l is implicitly transformed to new MyListExt.ops.MyListExtOps[.., ..](l) and generics are inferred to be [Nothing, MyList[Int]], which doesn't satisfy [T, A <: MyList[T]].
I can't see reason to parametrize MyListExt with both T and A <: MyList[T]. I guess T is enough, use MyList[T] instead of A.
Don't use private type T0, just parametrize myListToStreamImpl (make it def) with T0 aka T.
Try
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
trait MyListExt[T] {
def stream(a: MyList[T]): Stream[T]
}
object MyListExt {
def apply[T](implicit a: MyListExt[T]): MyListExt[T] = a
object ops {
implicit class MyListExtOps[T](val a: MyList[T]) extends AnyVal {
def stream(implicit ext: MyListExt[T]): Stream[T] = ext.stream(a)
}
}
implicit def myListToStreamImpl[T]: MyListExt[T] = new MyListExt[T] {
override def stream(a: MyList[T]): Stream[T] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
In my application I have multiple case classes and objects which are part of sealed trait hierarchy. I use them as messages in Akka.
Those classes need to be converted to user friendly form before sending through websocket.
Previously I used big pattern match to convert them in single place, but as number of types grows I would like to use implicit conversion:
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
trait Converter[T] {
def convert(t: T): Int
}
}
object Implicits {
import Types._
implicit object Type1Coverter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Coverter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
implicit object Type3Coverter extends Converter[SubType3.type] {
override def convert(t: SubType3.type): Int = 3
}
}
object Conversion {
import Types._
def convert[T: Converter](t: T): Int = {
implicitly[Converter[T]].convert(t)
}
def convert2[T <: Type](t: T)(implicit ev1: Converter[SubType1.type], ev2: Converter[SubType2.type], ev3: Converter[SubType3.type]): Int = {
t match {
case t1#SubType1 =>
implicitly[Converter[SubType1.type]].convert(t1)
case t2#SubType2 =>
implicitly[Converter[SubType2.type]].convert(t2)
case t3#SubType3 =>
implicitly[Converter[SubType3.type]].convert(t3)
}
}
}
I would like to use them as follow:
import Types._
import Conversion._
import Implicits._
val t1 = SubType1
val x1: Int = convert(t1)
val t: Type = SubType2 // T is of type Type
//Is it possible to handle that?
//val x: Int = convert(t)
val y: Int = convert2(t)
I would love to know if there is any "magic" way to generate something like convert2 automatically without writing a macro. Maybe there is already a library which provides macro like this?
Since you have no info at compile time about t's type, you have to work at runtime.
if you put your Converters in a sealed family, you could do something like the follwing, using a technique explained in this question:
import shapeless._
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
tsc: AllSingletons[A, T],
witness: Witness.Aux[H]): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
}
trait EnumerableAdt[A] {
def values: Set[A]
}
object EnumerableAdt {
implicit def fromAllSingletons[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]): EnumerableAdt[A] =
new EnumerableAdt[A] {
def values = singletons.values.toSet
}
}
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
sealed abstract class Converter[T <: Type: ClassTag] {
def convert(t: T): Int
def convertibleObjectClass = implicitly[ClassTag[T]].runtimeClass
}
object Implicits {
implicit object Type1Converter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Converter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
// let's pretend you FORGOT to add Type3Converter
// implicit object Type3Converter extends Converter[SubType3.type] {
// override def convert(t: SubType3.type): Int = 3
// }
}
}
object Conversion {
import Types._
val AllConverters: Map[Class[_], Converter[_ <: Type]] = implicitly[EnumerableAdt[Converter[_ <: Type]]].values
.map(c => c.convertibleObjectClass -> c).toMap
// You're sure you have all the converters here but you can't be sure you remembered to add one per subtype... you have to test it
// you are sure this cast doesn't fail anyway because of how you created the map
def findConverter[T <: Type](t: T) = AllConverters.get(t.getClass).asInstanceOf[Option[Converter[T]]]
def convert2[T <: Type](t: T): Option[Int] = findConverter(t).map(_.convert(t))
}
object Test extends App {
import Types._
import Conversion._
val t: Type = SubType2
val t2: Type = SubType3
// works, because a Converter[Subtype2.type] exists
val a: Option[Int] = convert2(t)
// returns None, because a Converter[Subtype3.type] doesn't exist
val b: Option[Int] = convert2(t2)
}