Function in generic class - scala

I have class Seq and I want to have method "multy" that adds number to List factors, but I want, that only Seq of Number types will have this method, for this example, val numbers should work with multy, and val strings shouldn't.
import scala.collection.mutable.ListBuffer
object Main extends App{
val strings = new Seq("f", "d", "a")
val numbers = new Seq(1,5,4,2)
val strings2 = new Seq("c", "b")
numbers.multy(5)
strings.multy(5)
val strings3 = strings2.concat(strings)
println(strings3)
println(numbers)
}
class Seq[T : Ordering] (initialElems: T*) {
override def toString: String = elems.toString
val factors = ListBuffer[Number](1)
val elems = initialElems.sorted
def concat(a:Seq[T]) = new Seq(a.elems ++ this.elems:_*)
def multy[T <: Number](a:Number) = {
factors += a;
}
}

If you want scala.Int, scala.Long, scala.Double, etc to not be supported - because they don't extend Number - you can define method as
def multy(a: Number)(implicit ev: T <:< Number): Unit = {
factors += a
}
However, considering that under the hood they could be extending Number (if the compiler, decides that it should compile them as objects and not as primitives), usage of a type class would work better:
trait IsNumber[T] {
def asNumber(value: T): Number
}
object IsNumber {
implicit def numbersAreNumbers[T <: Number]: IsNumber[T] = t => t
implicit val intIsNumber: IsNumber[Int] = i => (i: Number)
... // the same for Long, Short, etc
}
which could be used in multy as evidence
def multy(a: Number)(implicit ev: IsNumber[T]): Unit = {
factors += a
}
and as normal type class in code that would need that knowledge for something:
def doSomethingWithElements(implicit isNumber: IsNumber[T]) = {
elems.map(isNumber.asNumber).toList // List[Number]
}
This would support both java.lang.* Numbers as well as Scala's numbers definitions.

Related

Group TypeClass instances by type parameter

Suppose, I have 2 typeclasses:
trait Foo[A] {
...
}
trait Bar[A] {
...
}
and then I collect their instances into collections:
val seqFoo : Set[Foo[_]] = ...
val seqBar : Set[Bar[_]] = ...
is there a way to combine this seqs into something like this:
val fooBar = (Foo[Int],Bar[Int]), ... , (Foo[String],Bar[String])
Maybe pattern matching function or type tags is an answer, but I believe this case should have more straightforward solution
For example you can make your type classes abstract classes rather than traits (then they can have parameters), add implicit TypeTag parameters, and make groupBy for your collections.
import scala.reflect.runtime.universe.{TypeTag, Type}
// type class
abstract class Foo[A](implicit val ttag: TypeTag[A]) {
def foo(): String // dummy method just to distinguish instances upon checking
}
// instances
object Foo1 {
implicit val intFoo: Foo[Int] = new Foo[Int]() {
override def foo(): String = "Foo1.intFoo"
}
implicit val strFoo: Foo[String] = new Foo[String]() {
override def foo(): String = "Foo1.strFoo"
}
}
object Foo2 {
implicit val intFoo: Foo[Int] = new Foo[Int]() {
override def foo(): String = "Foo2.intFoo"
}
implicit val boolFoo: Foo[Boolean] = new Foo[Boolean]() {
override def foo(): String = "Foo2.boolFoo"
}
}
object Foo3 {
implicit val intFoo: Foo[Int] = new Foo[Int]() {
override def foo(): String = "Foo3.intFoo"
}
implicit val strFoo: Foo[String] = new Foo[String]() {
override def foo(): String = "Foo3.strFoo"
}
implicit val boolFoo: Foo[Boolean] = new Foo[Boolean]() {
override def foo(): String = "Foo3.boolFoo"
}
}
val seqFoo : Set[Foo[_]] = Set(Foo1.intFoo, Foo1.strFoo, Foo2.intFoo, Foo2.boolFoo, Foo3.intFoo, Foo3.strFoo, Foo3.boolFoo)
val grouped: Map[Type, Set[Foo[_]]] = seqFoo.groupBy(_.ttag.tpe)
// checking that instances are grouped by type
grouped.view.mapValues(_.map(_.foo())).foreach(println)
//(Int,HashSet(Foo3.intFoo, Foo1.intFoo, Foo2.intFoo))
//(String,HashSet(Foo1.strFoo, Foo3.strFoo))
//(Boolean,HashSet(Foo2.boolFoo, Foo3.boolFoo))
Simlarly you can do groupBy for Bar and then do whatever you want with Map[Type, Set[Foo[_]]] and Map[Type, Set[Bar[_]]]. For example merge the Maps
val grouped: Map[Type, Set[Foo[_]]] = ???
val grouped1: Map[Type, Set[Bar[_]]] = ???
val merged: Map[Type, (Set[Foo[_]], Set[Bar[_]])] =
(grouped.keySet union grouped1.keySet)
.map(tpe => tpe -> (grouped(tpe), grouped1(tpe)))
.toMap
I'll copy from my comment. Instances of type classes are intended to be resolved automatically (via implicit resolution) by compiler at compile time. Collecting the instances manually seems weird, so does collecting them at runtime.
My typeclasses instances implement decoder/encoder logic. Also they contain some meta information (name particularly). So i would like to check name-to-type accordance and generate unique names, based on how many instances have same name but different type parameter.
Although names of implicits can sometimes make impact on implicit resolution (1 2 3 4), normally you shouldn't be interested much in names of implicits, nor in name-to-type correspondence. Maybe you should provide some code snippet so that we can understand your setting and goals. Maybe what you need can be done at compile time and/or automatically.
Alternatively, if you prefer to keep type classes traits or you can't modify their code, you can use magnet pattern (1 2 3 4 5 6 7 8)
trait Foo[A] {
def foo(): String
}
implicit class Magnet[F[_], A: TypeTag](val inst: F[A]) {
def tpe: Type = typeOf[A]
}
val seqFoo = Set[Magnet[Foo, _]](Foo1.intFoo, Foo1.strFoo, Foo2.intFoo, Foo2.boolFoo, Foo3.intFoo, Foo3.strFoo, Foo3.boolFoo)
val grouped: Map[Type, Set[Magnet[Foo, _]]] = seqFoo.groupBy(_.tpe)
// checking that instances are grouped by type
grouped.view.mapValues(_.map(_.inst.foo())).foreach(println)
//(String,HashSet(Foo1.strFoo, Foo3.strFoo))
//(Int,HashSet(Foo3.intFoo, Foo1.intFoo, Foo2.intFoo))
//(Boolean,HashSet(Foo2.boolFoo, Foo3.boolFoo))
Using the "Prolog in Scala" to find available type class instances

Type inference for generic strategy pattern in Scala

What I would like to accomplish
I want to utilize a strategy pattern, whereas the strategy class has type parameters.
What the code looks like
Assume I have the following generic abstract strategy class:
abstract class Strategy[T, V]() {
def doSomething(x: Int): V
def unDoSomething(x: V): T
}
I now derive two concrete strategies:
class StrategyOne() extends Strategy[Int, String] {
def doSomething(x: Int): String = { x.toString() }
def unDoSomething(x: String): Int = { x.toInt }
}
class StrategyTwo() extends Strategy[Double, List[Int]] {
def doSomething(x: Int): List[Int] = { List(x, 10, 20)}
def unDoSomething(x: List[Int]): Double= { x.reduceLeft(_ + _) + 0.1 }
}
Now, we have a class which uses the strategy:
class Worker[T, V](strategy: Strategy[T, V]) {
def run() {
val res = strategy.doSomething(5) //res is a T
val res2 = strategy.unDoSomething(res) //res2 is a V
println(res2)
}
}
As expected, I am now able to instantiate new workers with out explicit types:
val worker1 = new Worker(new StrategyOne())
val worker2 = new Worker(new StrategyTwo())
Problem
However, I also want to make use of some kind of dynamic strategy selection, like this:
val strategies = Map("one" -> new StrategyOne(), "two" -> new StrategyTwo())
val worker = new Worker(strategies(args(0)))
Naturally, the compiler tells me that what I want is impossible, because no type can be inferred.
Question
I know that this constellation is unfortunate, but I need the types of T and V inside Worker.
Is it possible to make this kind of pattern work for this specific case?
Abstract type members should help you more than type parameters, here. Indeed, you mostly want to pass around Strategys without caring too much about their two types (including putting them in a map). And at one point (in the Worker), you need the types.
So I suggest the following (you should probably give more descriptive names to V and T in this model, but I couldn't figure out what they meant so I left them as is):
abstract class Strategy {
type T
type V
def doSomething(x: Int): V
def unDoSomething(x: V): T
}
class StrategyOne extends Strategy {
type T = Int
type V = String
def doSomething(x: Int): String = {...}
def unDoSomething(x: String): Int = {...}
}
class StrategyTwo extends Strategy {
type T = Double
type V = List[Int]
def doSomething(x: Int): List[Int] = {...}
def unDoSomething(x: List[Int]): Double= {...}
}
class Worker(strategy: Strategy) {
def run(): Unit = {
val res = strategy.doSomething(5) //res is a strategy.T
val res2 = strategy.unDoSomething(res) //res2 is a strategy.V
println(res2)
}
}
In this case, the types of res and res2 are inferred. But should you need to write their types down, they are strategy.T and strategy.V, as I wrote in the comments (path-dependent types, if you want to Google the concept).
You will still be able to create your strategies easily:
val worker1 = new Worker(new StrategyOne)
val worker2 = new Worker(new StrategyTwo)
and now you can also do this:
val strategies = Map("one" -> new StrategyOne, "two" -> new StrategyTwo)
val worker = new Worker(strategies(args(0)))
as you requested. And it'll all typecheck nicely.

Accessing class-level values of type parameters in Scala

I have a trait and a case class implementing it. One of the features of the trait that the implementations override is a default value. I can't find a good way to access this default value from a class that is parametrized by a specific implementation of that trait.
This is minimal code, so it doesn't really demonstrate the motivation anymore, but it does demonstrate the error:
import scala.language.implicitConversions
trait Distance[T] {
val Zero: T
def +( that: T ): T
}
case class DoubleDistance( val v: Double ) extends Distance[DoubleDistance] {
val Zero = DoubleDistance( 0.0 )
def +( that: DoubleDistance ) = DoubleDistance( v + that.v )
}
object DistanceImplicits {
implicit def DoubleToDistance( v: Double ) = new DoubleDistance( v )
}
class User[T<:Distance[T]] {
val default: T = T.Zero // This line gives me a compilation error
}
The error I get is
not found: value T
When I needed to construct an Array[T] inside my User class I could get that to work by adding implicit typetag:ClassTag[T] to my arguments, but that doesn't seem to have any effect here.
First, why this doesn't work: consider a different implementation of Distance.
case class DoubleDistance1(val v: Double) extends Distance[DoubleDistance1] {
val Zero = this
def +(that: DoubleDistance1) = ??? // doesn't matter
}
What would you expect DoubleDistance1.Zero to mean? You can make it work using a "type class":
trait DistanceOps[T] {
val zero: T
def add(d1: T, d2: T): T
}
// just to let you write distance1 + distance2
implicit class RichDistance[T](d: T)(implicit ops: DistanceOps[T]) {
def +(other: T) = ops.add(d, other)
}
case class DoubleDistance(v: Double)
object DoubleDistance {
implicit object DoubleDistanceOps extends DistanceOps[DoubleDistance] {
val zero = DoubleDistance(0.0)
def add(d1: DoubleDistance, d2: DoubleDistance) = DoubleDistance(d1.v + d2.v)
}
}
// how to use
class User[T](implicit ops: DistanceOps[T]) {
val default: T = ops.zero
}
This looks like a classic use case for the type class pattern. Rather than associating an instance of the Distance trait with each value of interest, you associate one with each type of interest:
trait Distance[T] {
val Zero: T
def +( a: T, b: T ): T
}
implicit object DoubleDistance extends Distance[Double] {
val Zero = 0.0
def +( a: Double, b: Double ) = a + b
}
class User[T : Distance] {
val default: T = implicitly[Distance[T]].Zero
}
Where is that Zero supposed to come from? Are you looking to do something like this?
class User[T<:Distance[T]] {
self:Distance[T] =>
val default: T = Zero
}

scala: add methods to an enum

I have a simple enum like this:
object ConditionOperator extends Enumeration {
val Equal = Value("equal")
val NotEqual = Value("notEqual")
val GreaterOrEqual = Value("greaterOrEqual")
val Greater = Value("greater")
val LessOrEqual = Value("lessOrEqual")
val Less = Value("less")
And I'd like to add a method to each enum so that I can use it like this:
def buildSqlCondition(field: String, operator: ConditionOperator.Value, value: String ) = {
val sqlOperator = operator.toSql
[...]
So, ConditionOperator.Equal.toSql wuld return "=", and ConditionOperator.NotEqual.toSql would return "<>", etc...
But I don't know how to define a toSql method, so that each enum can "see" it's own value and decide how to translate itself to a sql operator...
This is an example of what I have found for Scala 2.9.2 from various searches on the topic in the past:
object Progress extends Enumeration {
type enum = Value
val READY = new ProgressVal {
val isActive = false
def myMethod: Any = { .. }
}
val EXECUTE = new ProgressVal {
val isActive = true
def myMethod: Any = { .. }
}
val COMPLETE = new ProgressVal {
val isActive = false
def myMethod: Any = { .. }
}
protected abstract class ProgressVal extends Val() {
val isActive: Boolean
def myMethod: Any
}
implicit def valueToProgress(valu: Value) = valu.asInstanceOf[ProgressVal]
}
type Progress = Progress.enum
The implicit is key to making this usable.
The type enum and type Progress are somewhat redundant; I include them to present both concepts as something I've found helpful.
To give credit where it's due, the original idea for this came from Sean Ross in a response to a question of which this one is a duplicate.
You can start by defining an inner class that overrides Enumeration.Val. To simplify things, let's call it Value (we overload the original meaning of Value as defined in Enumeration).
So we have our new Value type which inherits Enumeration.Val which itself inherits Enumeration.Value.
Given that toSql has no side effects and returns a different string for each enumeration, you might as well just make it a val.
Finally, to make it fully usable, you'll want to have ConditionOperator.apply and ConditionOperator.withName to return your newly defined Value class instead of the Value type as defined in Enumeration.
Otherwise, when using apply or withName to look up an instance of ConditionOperator by index/name, you won't be able to call toSql because the enumeration type will not be specific enoough.
Ideally we'd like to just override apply and withName and add a cast to ConditionOperator.Value, but these methods are final.
However we can employ a small trick here: define new methods apply and withName with the same signature but an additional implicit parameter that will always be available (Predef.DummyImplicit fits this rolle perfectly).
The additional parameter ensures that the signature is different so that we are able to define these new methods, while at the same time being nearly indistinguishable from the original apply/withName methods.
The rules for overloading resolution in scala ensure that our new methods are the ones favored by the compiler (so we have in practice shadowed the original methods).
object ConditionOperator extends Enumeration {
// Here we overload the meaning of "Value" to suit our needs
class Value(name: String, val toSql: String) extends super.Val(name) {
def someFlag: Boolean = true // An example of another method, that you can override below
}
val Equal = new Value("equal", "=")
val NotEqual = new Value("notEqual", "<>")
val GreaterOrEqual = new Value("greaterOrEqual", ">=")
val Greater = new Value("greater", ">")
val LessOrEqual = new Value("lessOrEqual", "<=") { override def someFlag = false }
val Less = new Value("less", "<")
final def apply(x: Int)( implicit dummy: DummyImplicit ): Value = super.apply(x).asInstanceOf[Value]
final def withName(s: String)( implicit dummy: DummyImplicit ): Value = super.withName(s).asInstanceOf[Value]
}
You can check that you can now do things like ConditionOperator(2).toSql or ConditionOperator.withName("greaterOrEqual"), which both return ">=" as expected.
Finally, the above gymnastic can be abstracted away:
abstract class CustomEnumeration extends Enumeration {
type BaseValue = super.Val
type CustomValue <: super.Value
type Value = CustomValue
final def apply(x: Int)( implicit dummy: DummyImplicit ): CustomValue = super.apply(x).asInstanceOf[CustomValue]
final def withName(s: String)( implicit dummy: DummyImplicit ): CustomValue = super.withName(s).asInstanceOf[CustomValue]
}
object ConditionOperator extends CustomEnumeration {
class CustomValue(name: String, val toSql: String) extends BaseValue(name) {
def someFlag: Boolean = true
}
val Equal = new Value("equal", "=")
val NotEqual = new Value("notEqual", "<>")
val GreaterOrEqual = new Value("greaterOrEqual", ">=")
val Greater = new Value("greater", ">")
val LessOrEqual = new Value("lessOrEqual", "<=") { override def someFlag = false }
val Less = new Value("less", "<")
}
object ConditionOperator extends Enumeration {
implicit def overrideValue(v:Value) = new OverridedValue(v)
class OverridedValue(val v:Value) {
def toSql = v.toString
}
val Equal = Value("=")
val NotEqual = Value("<>")
val GreaterOrEqual = Value(">=")
val Greater = Value(">")
val LessOrEqual = Value("<=")
val Less = Value("<")
}
import ConditionOperator._
assert(Equal.toSql == "=")
And in scala 2.10, you can make it simpler by using implicit class, replace
implicit def overrideValue(v:Value) = new OverridedValue(v)
class OverridedValue(val v:Value) {
def toSql = v.toString
}
with
implicit class OverridedValue(val v:Value) {
def toSql = v.toString
}

Elegant way to sort Array[B] for a subclass B < A, when A extends Ordered[A]?

Having defined a class A which extends Ordering[A], and a subclass B of A, how do I automatically sort an Array of Bs? The Scala compiler complains that it "could not find implicit value for parameter ord: Ordering[B]". Here's a concrete REPL example (Scala 2.8), with A = Score and B = CommentedScore:
class Score(val value: Double) extends Ordered[Score] {
def compare(that: Score) = value.compare(that.value)
}
defined class Score
trait Comment { def comment: String }
defined trait Comment
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment
defined class CommentedScore
val s = new CommentedScore(10,"great")
s: CommentedScore = CommentedScore#842f23
val t = new CommentedScore(0,"mediocre")
t: CommentedScore = CommentedScore#dc2bbe
val commentedScores = Array(s,t)
commentedScores: Array[CommentedScore] = Array(CommentedScore#b3f01d, CommentedScore#4f3c89)
util.Sorting.quickSort(commentedScores)
error: could not find implicit value for parameter ord: Ordering[CommentedScore]
util.Sorting.quickSort(commentedScores)
^
How do I fix this (that is, sort an Array[B] = Array[CommentedScore] "for free", given that I know how to sort Array[A] = Array[Score]), in an elegant manner which avoids boilerplate?
Thanks!
Add the required implicit yourself:
implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)
You can put this in a CommentedScore companion object so that there is no boilerplate at use-site.
Edit: if you want the ordering method to be defined only at the top of the inheritance tree, you still have to provide an Ordering for each subclass, but you can define the compare method of the Ordering in terms of the one in the Score object. i.e.
object Score {
implicit val ord: Ordering[Score] = Ordering.by(_.value)
}
object CommentedScore {
implicit val csOrd = new Ordering[CommentedScore] {
def compare(x: CommentedScore, y: CommentedScore) = Score.ord.compare(x, y)
}
}
if you don't want to re-define this for each sub-class, you can use a generic method to produce the Ordering:
object Score {
implicit def ord[T <: Score]: Ordering[T] = Ordering.by(_.value)
}
This is a bit less efficient since being a def rather than a val, it creates a new Ordering each time one is required. However the overhead is probably tiny. Also note, the Ordered trait and compare method is not necessary now we have Orderings.
You might use Order from scalaz, which is contravariant, so you need not to define it for every subclass. Here is an example:
import scalaz._
import Scalaz._
class Score(val value: Double)
object Score {
implicit val scoreOrd: Order[Score] = orderBy(_.value)
}
trait Comment { def comment: String }
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment {
override def toString = s"cs($value, $comment)"
}
def quickSort[E: Order](list: List[E]): List[E] = list match {
case Nil => Nil
case head :: tail =>
val (less, more) = tail partition { e => implicitly[Order[E]].order(e, head) == LT }
quickSort(less) ::: head :: quickSort(more)
}
println(quickSort(List(
new CommentedScore(10,"great"),
new CommentedScore(5,"ok"),
new CommentedScore(8,"nice"),
new CommentedScore(0,"mediocre")
))) // List(cs(0.0, mediocre), cs(5.0, ok), cs(8.0, nice), cs(10.0, great))
This works:
val scoreArray: Array[Score] = Array(s, t)
util.Sorting.quickSort(scoreArray)
Or if you are starting from the Array[CommentedScore]:
val scoreArray: Array[Score] = commentedScores.map(identity)
util.Sorting.quickSort(scoreArray)
Note you can sort more simply with:
scoreArray.sorted