trait B {
type MyInnerType
def foo: MyInnerType
}
object B1 extends B {
type MyInnerType = Double
val foo = 3.0
}
trait A {
type MyInnerType
val b: B
def foo(x: b.MyInnerType): MyInnerType
def bar(y: MyInnerType): Unit
}
object A1 extends A {
type MyInnerType = Int
val b = B1
def foo(x: b.MyInnerType) = 1
def bar(y: MyInnerType) {}
}
object A2 extends A {
type MyInnerType = String
val b = B1
def foo(x: b.MyInnerType) = "a"
def bar(y: MyInnerType) {}
}
val as = Seq(A1, A2)
as foreach { a => a.bar(a.foo(a.b.foo)) } // wrong, a.foo(a.b.foo) infers to Any
However, if a.foo does not take parameters, everything works perfectly and a.foo infers to a.MyInnerType. It also works if I cast .asInstanceOf[a.MyInnerType]. Any explanations?
I'm running scala 2.9.1 and on the REPL I get this for as:
scala> val as = Seq(A1, A2)
as: Seq[ScalaObject with A{def foo(x: Double): Any; val b: B1.type; type MyInnerType >: java.lang.String with Int}] = List(A1$#6da13047, A2$#7168bd8b)
However, when I change it to val as:Seq[A] = Seq(A1, A2) I get:
scala> val as:Seq[A] = Seq(A1, A2)
as: Seq[A] = List(A1$#6da13047, A2$#7168bd8b)
scala> as foreach { a => a.bar(a.foo(a.b.foo)) }
Sometimes (all the time) scala has trouble inferring types, so you have to annotate what you want. I go to the REPL often to find out what's really going on.
Related
In particular, this minimal example:
trait A[T1, T2] {
def convert(t1: T1): T2
def reverse(t2: T2): T1
}
class B extends A[Int, Double] {
def convert(i: Int): Double = i.toDouble
def reverse(i: Double): Int = i.toInt
}
class C extends A[Int, Float] {
def convert(i: Int): Float = i.toFloat
def reverse(i: Float): Int = i.toInt
}
val bOrC: A[Int, _] = if (System.nanoTime % 2 == 0) {
new B
} else {
new C
}
bOrC.convert(7)
bOrC.reverse(bOrC.convert(7))
Will fail on the last line:
scala> bOrC.reverse(bOrC.convert(7))
<console>:12: error: type mismatch;
found : (some other)_$1(in value bOrC)
required: _$1(in value bOrC)
bOrC.reverse(bOrC.convert(7))
It seems that the type of _$1 is the same in both the return type and the argument - it's bOrC's T2 type, whatever it may be. Local type inference shouldn't be a problem here. Why can't I do this?
Is there a workaround that isn't as ugly as the following?
trait A[T1, T2] {
def convert(t1: T1): T2
def reverse(t2: X): T1
type X = T2
}
// ... rest as before
bOrC.reverse(bOrC.convert(7).asInstanceOf[bOrC.X])
Edit: looks like if you tell Scala it's the same type, everything is handled. This gets rid of the silly type X:
def thereAndBack[T2](a: A[Int, T2], b: Int) = a.reverse(a.convert(b))
thereAndBack(bOrC)
Perhaps you can treat A as a typeclass and only have one of B / C available implicitly?
def convert[T1, T2](x: T1)(implicit a: A[T1, T2]): T2 = {
a.convert(x)
}
def reverse[T1, T2](x: T2)(implicit a: A[T1, T2]): T1 = {
a.reverse(x)
}
implicit val b = new B
// or implicit val c = new C
convert(7)
reverse(convert(7))
Just started learning Scalaz. Here is my code
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
object Monoid {
implicit val IntMonoid: Monoid[Int] = new Monoid[Int] {
def mappend(a1: Int, a2: Int): Int = a1 + a2
def mzero: Int = 0
}
implicit val StringMonoid: Monoid[String] = new Monoid[String] {
def mappend(a1: String, a2: String): String = a1 + a2
def mzero: String = ""
}
}
trait MonoidOp[A] {
val F: Monoid[A]
val value: A
def |+|(a2: A): A = F.mappend(value, a2)
}
object MonoidOp{
implicit def toMonoidOp[A: Monoid](a: A): MonoidOp[A] = new MonoidOp[A]{
val F = implicitly[Monoid[A]]
val value = a
}
}
I have defined a function (just for the sake of it)
def addXY[A: Monoid](x: A, y: A): A = x |+| y
I want to lift it so that it could be used using Containers like Option, List, etc. But when I do this
def addXYOptioned = Functor[Option].lift(addXY)
It says error: could not find implicit value for evidence parameter of type scalaz.Monoid[A]
def addOptioned = Functor[Option].lift(addXY)
How to lift such functions?
Your method addXY needs a Monoid[A] but there is no Monoid[A] in scope when used in addXYOptioned, so you also need to add the Monoid constraint to addXYOptioned.
The next problem is that Functor.lift only lifts a function A => B, but we can use Apply.lift2 to lift a function (A, B) => C.
Using the Monoid from Scalaz itself :
import scalaz._, Scalaz._
def addXY[A: Monoid](x: A, y: A): A = x |+| y
def addXYOptioned[A: Monoid] = Apply[Option].lift2(addXY[A] _)
We could generalize addXYOptioned to make it possible to lift addXY into any type constructor with an Apply instance :
def addXYApply[F[_]: Apply, A: Monoid] = Apply[F].lift2(addXY[A] _)
addXYApply[List, Int].apply(List(1,2), List(3,4))
// List[Int] = List(4, 5, 5, 6)
addXYApply[Option, Int].apply(1.some, 2.some)
// Option[Int] = Some(3)
I have the code that instance.get returns value, and based on the type I process accordingly.
instance.get match {
case v:Range => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
case v:Encoding => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
...
}
In the code, I have duplication for the Range and Encoding type. How can I merge the two cases?
I tried the | operator, but it doesn't work.
case v:Range | v:Encoding
This can't work, because Range.size and Encoding.size are two completely different methods despite the fact that they are named the same. And same is true for Range.decode and Edncoding.decode.
So, when you write v.size, the type of v has to be known, it has to be either v:Encoding or v:Range, not v:Encoding|v:Range.
How to fix this? Make a common trait like this:
trait SomethingWithDecodeAndSize {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
And then, change the definitions of Range and Encoding:
class Range extends SomethingWithDecodeAndSize { ... }
class Encoding extends SomethingWithDecodeAndSize { ... }
Now you can just do case v: SomethingWithDecodeAndSize => ... in your match clause.
Also ... Don't do instance.get, that's bad taste. Do instead
instance match {
Some(v: SomethingWithDecodeAndSize) => ...
}
Update
If you cannot modify the definitions of the original classes, you can use an extractor:
object SomethingWithDecodeAndSize {
def unapply(a: Any): Option[SomethingWithDecodeAndSize] = a match {
case r: Range => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case r: Encoding => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case _ => None
}
}
Now, you can do case Some(SomethingWithDecodeAndSize(v)) => ... in your match.
An alternate solution to #Dima's in case you can't change definition of Range and Encoding (and there is no supertype with required methods):
trait RangeOrEncoding {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
implicit def liftRange(r: Range): RangeOrEncoding = new RangeOrEncoding {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
}
// similar conversion for Encoding
// can also be a local def
private def handleRangeOrEncoding(v: RangeOrEncoding) = {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
instance match {
case Some(v: Range) => handleRangeOrEncoding(v)
case Some(v: Encoding) => handleRangeOrEncoding(v)
...
}
I remember the cheerleaders in high school asking us, "How loose is your goose?"
scala> class C { def f(i: Int) = 2 * i }
defined class C
scala> class D { def f(i: Int) = 3 * i }
defined class D
scala> def test(x: Any) = x match { case y: { def f(i: Int): Int } => y.f(42) }
<console>:11: warning: a pattern match on a refinement type is unchecked
def test(x: Any) = x match { case y: { def f(i: Int): Int } => y.f(42) }
^
warning: there was one feature warning; re-run with -feature for details
test: (x: Any)Int
scala> test(new C)
res0: Int = 84
scala> test(new D)
res1: Int = 126
scala> test(42)
java.lang.NoSuchMethodException: java.lang.Integer.f(int)
at java.lang.Class.getMethod(Class.java:1786)
at .reflMethod$Method1(<console>:11)
at .test(<console>:11)
... 32 elided
I believe the answer was: "Loose, baby, loose."
Edit:
scala> import reflect.runtime._,universe._,language.reflectiveCalls
import reflect.runtime._
import universe._
import language.reflectiveCalls
scala> class C { def f(i: Int) = 2 * i }
defined class C
scala> class D { def f(i: Int) = 3 * i }
defined class D
scala> def f[A](a: A)(implicit tt: TypeTag[A]) = a match {
| case b: { def f(i: Int): Int }
| if tt.tpe <:< typeOf[{ def f(i: Int): Int }] =>
| b.f(42)
| }
<console>:19: warning: a pattern match on a refinement type is unchecked
case b: { def f(i: Int): Int }
^
f: [A](a: A)(implicit tt: reflect.runtime.universe.TypeTag[A])Int
scala> f(new C)
res0: Int = 84
scala> f(new D)
res1: Int = 126
scala> f(3) // now an ordinary MatchError
scala.MatchError: 3 (of class java.lang.Integer)
at .f(<console>:18)
... 32 elided
So you can express it as an ordinary type bounds:
scala> def f[A <: { def f(i: Int): Int }](a: A) = a.f(42)
f: [A <: AnyRef{def f(i: Int): Int}](a: A)Int
scala> f(new C)
res3: Int = 84
scala> f(17)
<console>:20: error: inferred type arguments [Int] do not conform to method f's type parameter bounds [A <: AnyRef{def f(i: Int): Int}]
f(17)
^
<console>:20: error: type mismatch;
found : Int(17)
required: A
f(17)
^
You still need to accept the cost of the reflective call, of course.
I need an heterogeneous, typesafe container to store unrelated type A, B, C.
Here is a kind of type-level specification :
trait Container {
putA(a: A)
putB(b: B)
putC(c: C)
put(o: Any) = { o match {
case a: A => putA(a)
case b: B => putB(b)
case c: C => putC(c)
}
getAllAs : Seq[A]
getAllBs : Seq[B]
getAllCs : Seq[C]
}
Which type is best suites to backed this container ?
Is it worth creating a Containerable[T] typeclass for types A, B, C ?
thks.
As other have suggested, you can leverage shapeless' Coproduct type. Here's an example.
// let's define a Coproduct of the two types you want to support
type IS = Int :+: String :+: CNil
// now let's have a few instances
val i = Coproduct[IS](42)
val i2 = Coproduct[IS](43)
val s = Coproduct[IS]("foo")
val s2 = Coproduct[IS]("bar")
// let's put them in a container
val cont = List(i, s, i2, s2)
// now, do you want all the ints?
val ints = cont.map(_.select[Int]).flatten
// or all the strings?
val strings = cont.map(_.select[String]).flatten
// and of course you can add elements (it's a List)
val cont2 = Coproduct[IS](12) :: cont
val cont3 = Coproduct[IS]("baz") :: cont2
Now this is of course not the most intuitive API for a generic container, but can easily encapsulate the logic inside a custom class using a Coproduct for representing the multiple types.
Here's a sketch of an implementation
import shapeless._; import ops.coproduct._
class Container[T <: Coproduct] private (underlying: List[T]) {
def ::[A](a: A)(implicit ev: Inject[T, A]) =
new Container(Coproduct[T](a) :: underlying)
def get[A](implicit ev: Selector[T, A]) =
underlying.map(_.select[A]).flatten
override def toString = underlying.toString
}
object Container {
def empty[T <: Coproduct] = new Container(List[T]())
}
Example
scala> type IS = Int :+: String :+: CNil
defined type alias IS
scala> val cont = 42 :: "foo" :: "bar" :: 43 :: Container.empty[IS]
cont: Container[IS] = List(42, foo, bar, 43)
scala> cont.get[Int]
res0: List[Int] = List(42, 43)
scala> cont.get[String]
res1: List[String] = List(foo, bar)
Miles Sabin wrote a post on unboxed union types; this is implemented as a CoProduct in his shapeless library:
shapeless has a Coproduct type, a generalization of Scala's Either to an arbitrary number of choices
I am definitely not an expert on shapeless, but if you create a new question with or edit your question with the shapeless tag then you can get any assistance needed with using CoProduct
You should look at Shapeless's HList or Coproduct; I wouldn't reinvent this myself.
Here is a first version, but I would to abstract over type :
trait Container {
def putInt(i: Int)
def putString(s: String)
def put(o: Any) = o match {
case i: Int => putInt(i)
case s: String => putString(s)
}
def getInts() : Seq[Int]
def getStrings() : Seq[String]
}
class MutableContainer extends Container {
val ints = mutable.ArrayBuffer[Int]()
val strings = mutable.ArrayBuffer[String]()
override def putInt(i: Int): Unit = ints += i
override def putString(s: String): Unit = strings += s
override def getStrings(): Seq[String] = strings
override def getInts(): Seq[Int] = ints
}
object TestContainer extends App {
val mc = new MutableContainer()
mc.put("a")
mc.put("b")
mc.put(1)
println(mc.getInts())
println(mc.getStrings())
}
Now trying to abstract over type
trait Container {
def getInts() : Seq[Int]
def getStrings() : Seq[String]
def put[T](t: T)
//def get[T] : Seq[T]
}
class MutableContainer extends Container {
val entities = new mutable.HashMap[Class[_], mutable.Set[Any]]() with mutable.MultiMap[Class[_], Any]
override def getStrings(): Seq[String] = entities.get(classOf[String]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[String]] //strings
override def getInts(): Seq[Int] = entities.get(classOf[Int]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[Int]]
//override def get[T]: Seq[T] = entities.get(classOf[T]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[T]]
override def put[T](t: T): Unit = entities.addBinding(t.getClass, t)
}
trait Containable[T] {
def typ : String
}
trait Cont {
implicit object IntContainable extends Containable[Int] {
override def typ: String = "Int"
}
implicit object StringContainable extends Containable[String] {
override def typ: String = "String"
}
}
object TestContainer extends App {
val mc = new MutableContainer()
mc.put("a")
mc.put("b")
mc.put(1)
println(mc.getInts())
println(mc.getStrings())
println(mc.entities.keys)
}
But i've got a problem with java.lang.Integer and Int…
I've been fighting to find a way to handle the following case where I would like to find a common view (or super class) that unifies the type parameters such that I can access a type class that compares apples to apples:
case class Foo[A](i:A) {
def cmp[B:Ordering, C <% B](b:B)(implicit ev: A => B) = implicitly[Ordering[B]].lt(i,b)
}
// Foo(1).cmp(2.0) works
// Foo(1.0).cmp(2) complains about evidence of Double => Int
Now, this can trivially be done with a simple function:
def cmp[A:Ordering](a1:A, a2:A) = implicitly[Ordering[A]].lt(a1,a2)
// cmp(Foo(1).a, 1.0)
// cmp(Foo(1.0).a, 1)
However, I want it to live as a method of Foo. Any ideas on what I can do to coerce it to use the view bounds?
You could rely on a type class. A bit heavy, but works:
trait Cmp[A,B] {
def cmp( a: A, b: B ): Boolean
}
trait LowPriorityCmpImplicits {
implicit def cmp1[A,B]( implicit conv: A => B, ord: Ordering[B] ) = new Cmp[A, B]{
def cmp( a: A, b: B ) = ord.lt(conv(a), b)
}
}
object Cmp extends LowPriorityCmpImplicits {
implicit def cmp2[A,B]( implicit conv: B => A, ord: Ordering[A] ) = new Cmp[A, B]{
def cmp( a: A, b: B ) = ord.lt(a, conv(b))
}
}
case class Foo[A](i:A) {
def cmp[B](b: B)(implicit cmp: Cmp[A,B]) = cmp.cmp( i, b )
}
The LowPriorityCmpImplicits trait is to avoid ambiguity when both types are the same (cmp2 will be favored over cmp1)
Test:
scala> Foo(1).cmp(2.0)
res0: Boolean = true
scala> Foo(1.0).cmp(2)
res1: Boolean = true
scala> Foo(1).cmp(2)
res2: Boolean = true
scala> Foo(2).cmp(1.0)
res3: Boolean = false
scala> Foo(2.0).cmp(1)
res4: Boolean = false
scala> Foo(2).cmp(1)
res5: Boolean = false