Let's say I have a function such as:
def foo[T<:U <:V](t:T): Unit
I want to know if there is a way of combining these two in a type W so that I can have:
def foo[T<: W](t: T): Unit
The use case for this is:
trait FooTrait{
type W
def foo[T<: W](t: T): Unit
}
I might have two different implementations of foo, one of them with a simple W1 type bound whereas the other one is T<:W1 <:W2 I want the more complex one to define a W3 so that I can have:
def foo[T<: W3](t: T): Unit
Similiarly, I want to be able to do these with type classes. So if I have:
def bar[T<:U :V](t:T): Unit
I want to have
def bar[T:X](t:T): Unit
The use case for this is essentially the same as the earlier case.
is this possible?
In the first part of your question, the syntax isn't even valid.
If you want to impose multiple upper bounds U, V on some type T,
you have to use with keyword anyway:
trait A
trait B
def f[X <: A with B](x: X): Unit = ???
This here doesn't work:
// def f[X <: A <: B](x: X): Unit = ??? // doesn't compile
To address the second part of your question, I would like to
explain why something like with doesn't work for typeclasses.
This here does work:
trait Foo[X]
trait Bar[X]
def g[X: Foo : Bar](x: X): Unit = ???
This here doesn't work:
// def g[X: Foo with Bar](x: X): Unit = ??? // nope
Why? Because
def foo[X: Y](x: X): Ret = ???
is actually a shortcut for
def foo[X](x: X)(implicit y: Y[X]): Ret = ???
If you would try to somehow amalgamate two different typeclasses Foo and Bar,
this would result in the following desugared code:
def foo[X](x: X)(implicit superPowerfulThing: (Foo somehowGluedWith Bar)[X]): Ret = ???
But this is obviously not something that you should want.
Instead, what you want is:
def foo[X](x: X)(implicit foo: Foo[X], bar: Bar[X])(x: X): Ret = ???
In this way, the two requirements Foo and Bar can be supplied independently,
which wouldn't work if you requested some superPowerfulThing that implements
both Foo and Bar at once.
Hope that clarifies why something works or doesn't work.
Andrey Tyukin has correctly point out that with is probably the answer for your first question and that the second question has no direct solution. However if you are OK with indirect solutions, you might work this around by introducing a new type class that will says that the target types belongs to the two original type classes. Here is a simple example for imaginary typeclasses Foo and Bar and for a base trait Base with a specific implementation ChildFooBar:
trait Foo[X] {
def doFoo(x: X): String
}
trait Bar[X] {
def doBar(x: X): String
}
trait Base {
type W[_]
def baz[T: W](t: T): String
}
class ChildFooBar extends Base {
import ChildFooBar._
type W[X] = FooAndBar[X]
override def baz[T: FooAndBar](t: T): String = {
val foo = implicitly[Foo[T]]
val bar = implicitly[Bar[T]]
foo.doFoo(t) + bar.doBar(t)
}
}
object ChildFooBar {
#implicitNotFound("The type should provide both implicit Foo and implicit Bar.")
case class FooAndBar[X](foo: Foo[X], bar: Bar[X])
object FooAndBar {
implicit def fromFooAndBar[X](implicit foo: Foo[X], bar: Bar[X]): FooAndBar[X] = FooAndBar(foo, bar)
}
// private is important here to avoid diversion of implicits
private implicit def toFoo[X](implicit fooAndBar: FooAndBar[X]): Foo[X] = fooAndBar.foo
private implicit def toBar[X](implicit fooAndBar: FooAndBar[X]): Bar[X] = fooAndBar.bar
}
Now if SomeClass is a member of both Foo and Bar typeclasses, then
case class SomeClass(foo: Int, bar: Double)
object SomeClass {
implicit val foo: Foo[SomeClass] = new Foo[SomeClass] {
override def doFoo(x: SomeClass) = s"foo = ${x.foo}"
}
implicit val bar: Bar[SomeClass] = new Bar[SomeClass] {
override def doBar(x: SomeClass) = s"bar = ${x.bar}"
}
}
the simple code
println(new ChildFooBar().baz(SomeClass(1, 2.0)))
will compile and work as expected.
Related
I'm interested if I can create method with similar idea:
def myMethod[T](param: T)(implicit oneOf: Either[TypeClass1[T], TypeClass2[T]]) = oneOf match ...
I've tried to use default parameters (I've seen somethin similar in akka):
def myMethod[T](param: T)(implicit t1: TypeClass1[T] = null, t2: TypeClass2[T] = null) =
if (t1 == null) ...
However, that way I cannot force scala compiler to find at least one of them.
Also, I've implemented implicit conversion from TypeClass1[T] to Left[TypeClass1[T], TypeClass2[T]] and from TC2 to Right, however Scala compiler ignores this conversions.
Is there any way to do something like this?
The obvious solution is to create a new typeclass that can be constructed using either TypeClass1 or TypeClass2. The new typeclass implements the functionality used by myMethod that is common to both and maps it to the appropriate methods on TypeClass1 or TypeClass2.
Here is an example:
trait TypeClass1[T] {
def showOne = println("Typeclass 1")
}
trait TypeClass2[T] {
def showTwo = println("Typeclass 2")
}
trait UnionTypeClass[T] {
def show
}
object UnionTypeClass {
implicit def t1[T](implicit ev: TypeClass1[T]) = new UnionTypeClass[T] {
def show = ev.showOne
}
implicit def t2[T](implicit ev: TypeClass2[T]) = new UnionTypeClass[T] {
def show = ev.showTwo
}
}
implicit object IntClass extends TypeClass1[Int]
implicit object StringClass extends TypeClass2[String]
def myMethod[T](param: T)(implicit ev: UnionTypeClass[T]) = {
ev.show
}
myMethod(0)
myMethod("hello")
This will print
Typeclass 1
Typeclass 2
In Scala 3 you might be able to use union type like so
trait Foo[A]
trait Bar[A]
given foo as Foo[Int] {}
def g[T](using Foo[T] | Bar[T]) = summon
foo[Int] // ok
You can use standard shapeless.OrElse or implicitbox.Priority or implicitlogic.Or from one of libraries
https://github.com/milessabin/shapeless
https://github.com/monix/implicitbox
https://github.com/Jasper-M/implicitlogic
def myMethod[T](param: T)(implicit oneOf: OrElse[TypeClass1[T], TypeClass2[T]]) = ???
// def myMethod[T](param: T)(implicit oneOf: Priority[TypeClass1[T], TypeClass2[T]]) = ???
// def myMethod[T](param: T)(implicit oneOf: Or[TypeClass1[T], TypeClass2[T]]) = ???
trait TypeClass1[T]
trait TypeClass2[T]
implicit val tc1: TypeClass1[Int] = ???
implicit val tc2: TypeClass2[String] = ???
myMethod(1) //compiles
myMethod("a") //compiles
Type classes OrElse, Priority are similar to UnionTypeClass from #Tim's answer but they prioritize t1, t2.
I have an implicit helper set up like this:
trait Helper[T] {
def help(entry: T): Unit
}
object Helpers {
implicit object XHelper extends Helper[X] {
override def help(entry: X): Unit = {println("x")}
}
implicit object YHelper extends Helper[Y] {
override def help(entry: Y): Unit = {println("y")}
}
def help[T](entry: T)(implicit helper: Helper[T]): Unit = {
helper.help(entry)
}
}
I would like to set up a collection of elements and run help on each of them. However, the following gives a compiler error because we can't guarantee all elements have matching Helpers:
val data = Seq[_](new X(), new Y())
data.foreach(entry => Helpers.help(entry))
If we had a generic type T we could enforce the implicit constraint on it with [T: Helper], but that doesn't work on _. How can I enforce that each element of data has a matching Helper?
In Scala context bound like class A[T: Typeclass] is just syntactic sugar for class A[T](implicit ev: Typeclass[T]). Unlike T <: Base or T >: Super, context bound is not really a part of a type signature, so you can't have a signature like val b: Box[T: Typeclass].
If you want to run typeclass operations on elements of some container, you'd have to pack relevant typeclass instances together with the values in the container.
A possible implementation of this may look as follows:
import language.higherKinds
import language.implicitConversions
// Class that packs values with typeclass instances
class WithTC[T, TC[_]](t: T)(implicit tc: TC[T]) {
// Some helper methods to simplify executing typeclass operations
// You may just make `t` and `tc` public, if you wish.
def apply[U](op: (TC[T], T) => U) = op(tc, t)
def apply[U](op: T => TC[T] => U) = op(t)(tc)
}
object WithTC {
// Implicit conversion to automatically wrap values into `WithTC`
implicit def apply[T, TC[_]](t: T)(implicit tc: TC[T]): WithTC[T, TC] =
new WithTC(t)(tc)
}
Then you can make a sequence with existentially typed elements:
import Helpers._
val data: Seq[(T WithTC Helper) forSome { type T }] = Seq(new X(), new Y())
And execute typeclass operations on the sequence elements:
// The following lines produce equivalent results
data.foreach(_(_ help _))
data.foreach(_(t => implicit tc => Helpers.help(t)))
data.foreach(_(t => Helpers.help(t)(_)))
It's not possible with type like Seq since it is only parametrized for one element type that is common for all its elements.
However, you can achieve this with Shapeless HLists and polymorphics functions (Poly):
class X
class Y
trait Helper[T] {
def help(entry: T): Unit
}
object Helpers {
implicit object XHelper extends Helper[X] {
override def help(entry: X): Unit = println("x")
}
implicit object YHelper extends Helper[Y] {
override def help(entry: Y): Unit = println("y")
}
}
import shapeless._
object helper extends Poly1 {
implicit def tCase[T: Helper]: Case.Aux[T, Unit] =
at(implicitly[Helper[T]].help(_))
}
val hlist = new X :: new Y :: HNil
hlist.map(helper)
// Output:
x
y
I got the following issue when trying to use typeclasses throughout my project.
trait FooAble[T] { def fa(t: T): List[T] }
object Foo { def apply[T](t: T) = implicitly[FooAble[T]].fa(t) }
trait BarAble[T] { def fb(t: T): Double }
object Bar { def apply[T](t: T) = implicitly[BarAble[T]].fb(t) }
And would like to be able to do the following:
// xs contains elements of type A and B which are subclasses of the trait Something
def f(xs: List[Something]) = {
val something = xs.map(Foo)
val somethingElse = xs.map(Bar)
}
However, this would not work as we don't know if Something implements A[]and B[], no implicit implementation found. What do I need to do so that the elements of the list xs implement the typeclasses FooAble and BarAble?
I think this question: What are type classes in Scala useful for? will help you to understand the proper use (& usefulness) of type classes.
Am just extending the answer by Kevin Wright in the above link for your use case (if I understand your need correctly!):
trait Addable[T] {
def zero: T
def append(a: T, b: T): T
}
trait Productable[T] {
def zero: T
def product(a: T, b: T): T
}
implicit object IntIsAddable extends Addable[Int] {
def zero = 0
def append(a: Int, b: Int) = a + b
}
implicit object IntIsProductable extends Productable[Int] {
def zero = 1
def product(a: Int, b: Int) = a*b
}
def sumAndProduct[T](xs: List[T])(implicit addable: Addable[T], productable: Productable[T]) =
(xs.foldLeft(addable.zero)(addable.append), xs.foldLeft(productable.zero)(productable.product))
So akin to above, in your use case, you need to provide implicit objects which implement your type classes FooAble & BarAble and your method signature for function f becomes:
def f[Something](xs: List[Something])(implicit fooable: FooAble[Something], barable: BarAble[Something])
Is it possible to constrain a Scala generic type to only types that have overloaded a specific operator?
Example:
def foo[T](...):T = {...}
foo(...) * .70
Searching Google has yet to produce a solution. I considered restricting T to be of type Numeric (or scala's equivalent), but then I want to allow users to define custom types and specify their own behaviors for these operators.
Use a typeclass.
trait Multiply[A] {
def multiply(x: A, y: Double): A
}
object Multiply {
def apply[A](implicit instance: Multiple[A]): Multiply[A] = instance
trait Ops[A] {
def typeClassInstance: Multiply[A]
def self: A
def *(y: Double): A = typeClassInstance.multiply(self, y)
}
trait ToMultiplyOps {
implicit def toMultiplyOps[A](target: A)(implicit tc: Multiply[A]): Ops[A] = new Ops[A] {
val self = target
val typeClassInstance = tc
}
}
trait AllOps[A] extends Ops[A] {
def typeClassInstance: Multiply[A]
}
object ops {
implicit def toAllMultiplyOps[A](target: A)(implicit tc: Multiply[A]): AllOps[A] = new AllOps[A] {
val self = target
val typeClassInstance = tc
}
}
}
(Note that this is equivalent to what's generated by Michael Pilquist's simulacrum library, so you don't really need all this boilerplate)
Then your users can do this:
case class Foo(x: Int)
object Foo {
implicit val multiplyFoo: Multiply[Foo] = new Multiply[Foo] {
def multiply(foo: Foo, y: Double): Foo = ???
}
}
Foo(42) * 3.1415
Yes, there are so-called structural types. You can define them as follows:
def foo[T <: {def yourOperator:Unit}(...) : T = {...}
where yourOperator is the name of the method definition and Unit the return type. In this example T will accept every type which is declaring a method called yourOperator with Unit as return type.
This could be used for example to handle a resource which is Closeable. Imagine the following code.
def operatorOnResource[T <: {def close : Unit}](resource: T) : Unit = {
//do stuff with the resource
resource.close
}
Please note that this example is also kind of a risk, because T has only constraints on its structure. Hence, even if T satisfies the structural needs the semantic of the close could be different.
Lets say we want to use type classes to implement pretty printing:
trait Printer[T] {def print(t: T)}
with default implementation for ints:
implicit object IntPrinter extends Printer[Int] {
override def print(i : Int): Unit = println(i)
}
Our specific types we want to print are:
trait Foo {
type K
val k: K
}
class IntFoo extends Foo {
override type K = Int
override val k = 123
}
cool. Now I want to build printers for all Foos with printable Ks
implicit def fooPrinter[FP <: Foo](implicit ev: Printer[FP#K]): Printer[FP] =
new Printer[FP] {
override def print(f: FP): Unit = {
Predef.print("Foo: ")
ev.print(f.k)
}
}
lets check that implicits are resolved:
def main(args: Array[String]) {
implicitly[Printer[Int]]
implicitly[Printer[IntFoo]]
}
scalac 2.11.2 says:
diverging implicit expansion for type Sandbox.Printer[Int]
starting with method fooPrinter in object Sandbox
implicitly[Printer[Int]]
whaat?
OK, lets rewrite fooPrinter:
implicit def fooPrinter[KP, FP <: Foo {type K = KP}](implicit ev: Printer[KP]) =
new Printer[FP] {
override def print(f: FP): Unit = {
Predef.print("Foo: ")
ev.print(f.k)
}
}
this works in 2.11, but what's the problem with the first approach?
Unfortunately we're on 2.10, and second solution still doesn't work. It compiles until we add one more sime printer like
implicit object StringPrinter extends Printer[String] {
override def print(s : String): Unit = println(s)
}
and it mysteriously breaks Printer[IntFoo] implicit:
could not find implicit value for parameter e:
Sandbox.Printer[Sandbox.IntFoo]
compiler bugs?
Order of implicit declarations matters. In your source code reorder original code from
implicit object IntPrinter ...
...
implicit def fooPrinter ...
to
implicit def fooPrinter ...
...
implicit object IntPrinter ...