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 ...
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 written this code
trait Input[F[_]] {
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = for {
_ <- write("What is your name")
name <- read
} yield name
}
This code doesn't compile obviously because the compiler has no way of knowing that the type F supports flatmap. So I change my code to
import scalaz._
import Scalaz._
trait Input[F[_] : Monad] {
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = for {
_ <- write("What is your name")
name <- read
} yield name
}
but now I get compile time error traits cannot have type parameters with context bounds.
So how can I specify constraints on my type parameter so that it always supports flatmap?
trait Input[F[_]: Monad] would create an implicit constructor parameter and traits can't have constructor parameters (until Scala 3). def testFunc[F[_]: Monad] would create an implicit parameter. For instance:
def testFunc[F[_]: Monad](arg: Int) = ???
class TestClass[F[_]: Monad] {}
Will work because it is translated to:
def testFunc[F[_]](arg: Int)(implicit ev: Monad[F]) = ???
class TestClass[F[_]](implicit val ev: Monad[F]) {}
I.e. [F[_]: Monad] is syntactic sugar for [F[_]] with implicit val ev: Monad[F]. And traits has no constructor to pass parameters until Scala 3.
For your case, if you really need to inside a trait to constraint F to a Monad for example, then:
trait Input[F[_]] {
val M: Monad[F]
def read: F[String]
def write(str: String) : F[Unit]
def getName : F[String] = M.flatMap(write("What is your name"))(_ => read)
}
I.e. you are saying to one who implements, that "you can implement Input, as soon as you have Monad[F]". Then you can use it like:
object Main extends App{
class IOInput extends Input[IO] {
override val M: Monad[IO] = Monad[IO]
override def read: IO[String] = IO("red")
override def write(str: String): IO[Unit] = IO(println(s"write: $str"))
}
val impl = new IOInput
println(impl.getName.unsafeRunSync())
}
P.S. But for me, it seems like something is wrong. You are kinda defining effects in trait Input and using them right in the same trait. Reads weird for me at least. Probably getName should be somewhere else.
(Scala 2.11.8)
Consider the following code:
object ScalaTest extends App {
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
(new Wrapper).init()
}
I have a bunch of questions regarding this piece of code:
Why doesn't IntTC get resolved in the first place?
Why it compiles after being used once? (if you comment out the first invocation, code works)
Where should typeclass implicits be placed to get resolved properly?
Use a val with a explicit return type. See https://github.com/scala/bug/issues/801 and https://github.com/scala/bug/issues/8697 (among others).
Implicit objects have the same issue as implicit vals and defs with inferred return types. As for your second question: when IntTC is used explicitly you force the compiler to typecheck it, so after that point its type is known and can be found by implicit search.
class Wrapper {
import Wrapper._
def init(): Unit = {
// Compiles
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit val IntTC: TC[Int] = new TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
If you really want your implicit to be evaluated lazily like an object, you can use an implicit lazy val with an explicit type.
Define the implicit before the use of it.
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
(new Wrapper).init()
I'm trying to add an implicit value to (what I believe is) the companion object of a case class, but this implicit value is not found.
I'm trying to achieve something like the following:
package mypackage
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = ...
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
...
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClase] = ...
}
case class MyCaseClass(s: String) {
// some other methods
}
I've explicitly added the package here to show that both the MyCaseClass case class and object should be in scope. I know that the object is actually being constructed because I can get this to compile if I add
implicit val serializer = MyCaseClass.serializer
to main (though notably not if I add import MyCaseClass.serializer).
I'm concerned that the MyCaseClass object is not actually a companion of the case class, because if I explicitly define apply and unapply on the object and then attempt to call MyCaseClass.apply("string") in main, the compiler gives the following error:
ambiguous reference to overloaded definition,
both method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
and method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
match argument types (String)
val a = InputRecord.apply("string")
^
If it's not possible to take this approach, is there a way to use type classes with case classes without creating an implicit value every time it must be brought into scope?
EDIT: I'm using scala 2.10.3.
EDIT 2: Here's the example fleshed out:
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
// the above line makes the compiler complain that there is no
// Serializer[MyCaseClass] in scope
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
// implicits aren't found here
implicit val serializer: Serializer[MyCaseClass] = new Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
case class MyCaseClass(s: String) {
// some other methods
}
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
This actually compiles, though. I am getting this issue when using Scoobi's WireFormat[T] instead of Serializer, but can't provide a concise, runnable example due to complexity and the Scoobi dependency. I will try to create a more relevant example, but it seems as though the issue is not as general as I thought.
It turns out that the type class instances actually need to be implicit values, rather than objects. The MyCaseClass object above works because its serializer is assigned to an implicit value. However, this implementation
object MyCaseClass {
implicit object MyCaseClassSerializer extends Serializer[MyCaseClass] {
override def write(out: DataOutput, t: MyCaseClass): Unit = {
out.writeUTF(t.s)
}
}
}
fails with the error
Main.scala:9: error: could not find implicit value for evidence parameter of type mypackage.Serializer[mypackage.MyCaseClass]
serialize(out, caseClassInstance)
^
In my real code, I was using an auxiliary function to generate the Serializer[T] (see https://github.com/NICTA/scoobi/blob/24f48008b193f4e87b9ec04d5c8736ce0725d006/src/main/scala/com/nicta/scoobi/core/WireFormat.scala#L137). Despite the function having its own explicit return type, the type of the assigned value was not being inferred correctly by the compiler.
Below is the full example from the question with such a Serializer-generator.
package mypackage
import java.io.{DataOutput, DataOutputStream}
object Main {
import Serializer._
def main(args: Array[String]): Unit = {
val caseClassInstance = MyCaseClass("string")
val out: DataOutput = new DataOutputStream(System.out)
serialize(out, caseClassInstance)
}
def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
implicitly[Serializer[T]].write(out, t)
}
}
object MyCaseClass {
import Serializer._
// does not compile without Serializer[MyCaseClass] type annotation
implicit val serializer: Serializer[MyCaseClass] =
mkCaseSerializer(MyCaseClass.apply _, MyCaseClass.unapply _)
}
case class MyCaseClass(s: String)
trait Serializer[T] {
def write(out: DataOutput, t: T): Unit
}
object Serializer {
// does not compile without Serializer[String] type annotation
implicit val stringSerializer: Serializer[String] = new Serializer[String] {
override def write(out: DataOutput, s: String): Unit = {
out.writeUTF(s)
}
}
class CaseClassSerializer[T, A : Serializer](
apply: A => T, unapply: T => Option[A]) extends Serializer[T] {
override def write(out: DataOutput, t: T): Unit = {
implicitly[Serializer[A]].write(out, unapply(t).get)
}
}
def mkCaseSerializer[T, A : Serializer]
(apply: A => T, unapply: T => Option[A]): Serializer[T] =
new CaseClassSerializer(apply, unapply)
}
This related, simple code below prints 1.
object A{
implicit def A2Int(a:A)=a.i1
}
case class A(i1:Int,i2:Int)
object Run extends App{
val a=A(1,2)
val i:Int=a
println(i)
}
Suppose that I have the following scala code:
trait ValueSource[A] {
def value(a: Int): A
}
trait ValueSourceOps[A] {
def self: Int
def F: ValueSource[A]
def value: A = F.value(self)
}
trait ToValueSourceOps {
implicit def toValueSourceOps[A](index: Int)(implicit F0: ValueSource[A]): ValueSourceOps[A] = new ValueSourceOps[A] {
def self = index
def F: ValueSource[A] = F0
}
}
object Test extends ToValueSourceOps {
def value[A: ValueSource](index: Int): A = toValueSourceOps(index).value
}
The code above compiles well, but when I change the last line (body of method "value" in object Test) to
def value[A: ValueSource](index: Int): A = index.value
the compiler complains that
could not find implicit value for parameter F0: ValueSource[A]
In my opinion, def value[A: ValueSource] means I have a implicit value "ValueSource[A]", then why does the compilation fail?
The A in toValueSourceOps has no relationship with the A in value, which makes inferring it problematic. To me the real question is why it works when you call the method explicitly.
I'm guessing that, when toValueSourceOp is called explicitly, it has to infer the same A because that's the only implicit available.