Generic types in Scala - scala

I want to overloading constructor of abstract class with specific type. For example, I have:
abstract class Polinom(v: T)
So, when I create Polinom[String], I want to call constructor(String), for Int I want to call constructor(Int). If T != String and T != Int then I call constructor(T). In addition, for T == Int my object must have method add, for T == String - reverse, for T != String and T != Int object doesn't has this methods. How can I do that?

You can use evidence parameters for this:
class Polinom[T](v: T) {
def add(i: Int)(implicit ev: T <:< Int) = v + i
def reverse(implicit ev: T <:< String): String = ev(v).reverse
}
val x = new Polinom(50)
val y = new Polinom("hello")
val z = new Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
If you want specific constructors for Int and String and can't get enough of that implicit evidence, you can do this:
def this(i: Int)(implicit ev: Int =:= T) = this({
//do special int stuff here
println("I am in the special int constructor")
ev(i)
})
def this(s: String)(implicit ev: String =:= T) = this({
//do special string stuff here
println("I am in the special string constructor")
ev(s)
})
EDIT: Apparently, the above didn't work for the OP, although it seems to be working for me, but you can always make a companion object and overload the apply method, as the other answers suggested.
class Polinom[T] private(v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = new Polinom(i)
def apply(s: String): Polinom[String] = new Polinom(s)
def apply[T](x: T): Polinom[T] = new Polinom(x)
}
val x = Polinom(50)
val y = Polinom("hello")
val z = Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
Link to Scastie (the demo's below)
<script src="https://scastie.scala-lang.org/j8fWjvVFS3CumCo3WbUgqQ.js"></script>

It would be better to model that as an ADT, something like:
sealed trait Polinom[T] {
def v: T
}
object Polinom {
final case class IntPolinom private[Polinom] (v: Int) extends Polinom[Int] {
def add(x: Int): IntPolinom =
this.copy(v = this.v + x)
}
final case class StrPolinom private[Polinom] (v: String) extends Polinom[String] {
def reverse: StrPolinom =
this.copy(v = this.v.reverse)
}
final case class GenericPolinom[T] private[Polinom] (v: T) extends Polinom[T]
def apply[T](v: Int): IntPolinom =
IntPolinom(v)
def apply[T](v: String): StrPolinom =
StrPolinom(v)
def apply[T](v: T): GenericPolinom[T] =
GenericPolinom(v)
}

abstract class Polinom[T](v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = constructor(i)
def apply(s: String): Polinom[String] = constructor(s)
def apply[T](v: T): Polinom[T] = constructor(v)
}
Polinom(0)
Polinom("hello")
Polinom(None)
For examples of the add and reverse methods, see the other answers to this question.

Related

Get case class parameter types as a HList

I'm trying to generate instances of case class using shapeless
This works for generating instances of Foo
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types i.e. would like to convert case class Foo(x: Int, y: String) to classOf[Int] :: classOf[String] :: HNil. Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList like this:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ⹼沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
You can see the code running here.
Using built-in Shapeless type classes you can do
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞꨸ዤࠒ훿柲籐妭蝱⻤)

Constrain return type of a function that accepts Either

I am trying to make a function like this:
def foo(x: Either[String, Int]) = x match {
case Left(s) => Left("foo:" + s)
case Right(n) => Right(n+1)
}
This works, but I am looking for a way to assure the caller, that the result will always be of the same type as input - if input is Left, you get Left back, if it was Right, you get Right.
Can someone think of a neat trick I could use to do that?
I know, I can do this:
def foo[T <: Either[String, Int]](x: T): T = (x match {
case Left(s) => Left("foo:" + s)
case Right(n) => Right(n+1)
}).asInstanceOf[T]
... but the cast in the end is ugly :(
This declaration is going to be an abstract member of a base trait, that several implementation "plugins" will need to override, and I don't want to make all of them to have to do this type-casting thing.
I could also make two separate functions fooString, and fooInt ... but that is something I'd like to avoid, because of some considerations, specific to the particular api I am working on.
Any other ideas?
If you are not restricted to using Either, you can use type classes -
sealed trait Transformer[A] {
def transform(n: A): A
}
object Transformer {
implicit object IntTransformer extends Transformer[Int] { def transform(n: Int) = n + 1 }
implicit object StringTransformer extends Transformer[String] { def transform(s: String) = "foo:" + s }
}
def foo[A: Transformer](x: A)(implicit transformer: Transformer[A]) = transformer.transform(x)
This signature doesn't actually say what you want it to say:
val x = Left("a")
val y = foo[x.type](x)
y's type is x.type and so it must be the same instance, which it isn't. It follows that you need to change the signature if you want to avoid a cast. One approach (not tested):
trait LowPriorityFooImplicits { _: FooImplicits =>
implicit def eitherFoo(x: Either[String, Int]): Foo[Either[String, Int]] = new Foo(x) {
def foo() = x match {
case y: Left[String, Int] => y.foo()
case z: Right[String, Int] => z.foo()
}
}
trait FooImplicits extends LowPriorityFooImplicits {
sealed trait Foo[A <: Either[String, Int]](x: A) {
def foo(): A
}
implicit def leftFoo(x: Left[String, Int]): Foo[Left[String, Int]] = new Foo(x) {
def foo() = Left(fooString(x.value))
}
implicit def rightFoo ...
// x will be implicitly converted from a subtype of Either[String, Int]
def foo[A](x: Foo[A]): T = x.foo()
protected def fooString(s: String) = "foo:" + s
protected def fooInt(n: Int) = n + 1
}
(It still has fooString and fooInt, but not in the public API.)

How use implicit conversion to be able to use a typeclass pattern of different type

There is a good way to make the line 1.print works without defining an implicit intPrintable?
I would like to say to the compiler to use the stringPrintable implementation also for Int type without provide a new implicit Printable[Int], the idea is to say to compiler that Int can be viewed as String
Here the example:
trait Printable[T]{
def print(in: T): String
}
object Printable{
def apply[T](f: T => String): Printable[T] = new Printable[T] {
def print(in: T): String = f(in)
}
}
implicit class PrintableOps[T](v: T)(implicit printable: Printable[T]) {
def print: String = printable.print(v)
}
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
// doesn't works
1.print
// works
stringPrintable.print(1)
// works
intToString(1).print
Your code is requiring the additional implicit, because it is required as a constructor for your (implicit class) PrintableOps
You can simplify this by simply declaring implicit classes more directly:
trait Printable[T] {
def print: String
}
implicit class GenericPrintable[T](in: T) extends Printable[T] {
def print:String = in.toString
}
implicit class StringPrintable(in:String) extends Printable[String]{
override def print:String = s"print ${in}"
}
println( 1.print )
println( "1".print )
Your stringPrintable would require to use intToString to convert Int to String.
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
Printable.apply() requires an anonymous function and an anonymous function can't take an implicit value where intToString is implicit.
A better workaround is to statically define an implicit Printable[Int] or reform the Printable to GenericPrintable[T] with reference to #Jon Anderson
We need to provide an implicit conversion from Printer[String] => Printer[Int] given an implicit conversion from Int => String. We can put this on Printer companion object:
implicit def apply[T0, T1](implicit pin: Printable[T0], c: T1 => T0): Printable[T1] = new Printable[T1] {
def print(in: T1): String = pin.print(c(in))
}
Here the solution:
trait Printable[T]{
def print(in: T): String
}
object Printable{
def apply[T](f: T => String): Printable[T] = new Printable[T] {
def print(in: T): String = f(in)
}
implicit def apply[T0, T1](implicit pin: Printable[T0], c: T1 => T0): Printable[T1] = new Printable[T1] {
def print(in: T1): String = pin.print(c(in))
}
}
implicit class PrintableOps[T](v: T)(implicit printable: Printable[T]) {
def print: String = printable.print(v)
}
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
// now working
1.print
// works
stringPrintable.print(1)
// works
intToString(1).print
// don't compile, and it's ok, because no implicit conversion (A => String) is provided
case class A(in: String)
A("A").print
What do you think?

Class with its own context bound

The following works:
trait Context[T] {
def context(x: T): String
class Foo[T : Context](x: T) {
def bar() = implicitly[Context[T]].context(x)
}
implicit val c = new Context[Double] {
override def context(x: Double): String = "I am a double"
}
val f = new Foo(2.0)
f.bar() // I am a double
So I thought... is it also possible if I construct a class who has its own Context definition in it?
object Foo {
def apply[T : Context](x: T) = new Foo[T](x)
def apply[T](x: T, contextFunc: T => String): Foo[T] with Context[T] = new Foo[T](x) with Context[T] {
override def context(x: T): Double = contextFunc(x)
}
}
val f2 = Foo[Double](2.0, x => "I am still a double")
But it starts complaining that the implicit evidence is missing in the 2nd apply function. I can imagine that, since it looks like it starts to make the Foo-class first and then start to make the Context[T] trait.
Is there a way to solve this? In other words? Is there a way to construct a Foo class that has its own Context[T]?
The simplest way is probably to construct a context object and explicitly pass it as an argument, when constructing Foo:
def apply[T](x: T, contextFunc: T => String): Foo[T] =
new Foo(x)(new Context[T] {
def context(t: T) = contextFunc(t)
})

Scala: recursive implicit type

I have the following traits for parsing that give file positions for the beginning and end of the object:
case class FilePosn(lineNum :Int, tabs: Int, spaces: Int, fileName: String)
{/*code omitted*/}
trait PosnEnds
{
def startPosn: FilePosn
def endPosn: FilePosn
def multiLine: Boolean = startPosn.lineNum != endPosn.lineNum
def OneLine: Boolean = startPosn.lineNum == endPosn.lineNum
def indent: Int = startPosn.tabs
def startLine: Int = startPosn.lineNum
def endLine: Int = endPosn.lineNum
}
object FilePosnVoid extends FilePosn(0, 0, 0, "There is no File position")
{ override def posnString(indentSize: Int): String = "No File Posn: " }
In the companion object I create an implicit, so sequences of PosnEnds are themselves implicitly PosnEnds:
object PosnEnds
{
implicit class ImpPosnEndsSeq[A <: PosnEnds](thisSeq: Seq[A]) extends PosnEnds
{
override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)
}
}
Is there anyway to use implicits recursively so a Seq[Seq[A]] and a Seq[Seq[Seq[A]]] etc will be implicitly converted to a PosnEnds trait? In practice I probably won't need huge levels of depth, but it would be nice to use an elegant solution that implicitly converted Seq of arbitrary depth.
Currently for depth 2 I'm using:
implicit class ImpPosnEndsSeqSeq[A <: PosnEnds](thisSeq: Seq[Seq[A]]) extends PosnEnds
{
override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)
}
Yes. You could do it with typeclass mediator.
I allow myself to do some minor changes in your example to make it more reproducible. Inside object PosnEnds I have
val void = new FilePosn(0, 0, 0, "There is no File position") {
override def posnString(indentSize: Int): String = "No File Posn: "
}
def empty = new PosnEnds {
def startPosn: FilePosn = void
def endPosn: FilePosn = void
}
Thing you need first is some simple typeclass like
trait MakePosnEnds[X] extends (X => PosnEnds)
Now you can introduce canonical elements for induction:
implicit object idMakePosnEnds extends MakePosnEnds[PosnEnds] {
def apply(x: PosnEnds) = x
}
implicit def seqMakePosnEnds[X](implicit recur: MakePosnEnds[X]) = new MakePosnEnds[Seq[X]] {
def apply(x: Seq[X]): PosnEnds = new PosnEnds {
val thisSeq = x.map(recur)
override def startPosn: FilePosn = thisSeq.headOption.fold(void)(_.startPosn)
override def endPosn: FilePosn = thisSeq.lastOption.fold(void)(_.endPosn)
}
}
Finally you can define your implicit conversion
implicit def toPosnEnds[X](x: X)(implicit make: MakePosnEnds[X]): PosnEnds = make(x)
From this point
Seq(Seq(Seq(empty))).startLine
compiles and runs succesfully
Major difference with your attempt: we dont wait implicit conversion to stack. Implicit resolution can be recursive, but implicit conversion can not.
So we are using some value-less type, i.e something that could be achieved using only implicit arguments which means could be constructed by the compiler.
And only then projecting this logic to the concrete value.