Scala generic functions - scala

I have an abstract class
abstract class Foo {
def foo(a: Int): Int
...
}
// Usage
new Foo {
def foo(a: Int) = {
println("Foo")
a
}
}
I frequently see a companion object to make this a little less verbose for callers (e.g. the Play framework).
object Foo {
def apply(f: Int => Int) = new Foo {
def foo(a: Int) = f(a)
}
}
// Usage
Foo { a =>
println("Foo")
a
}
But suppose I make the method generic
abstract class Foo {
def foo(a: T): T
...
}
// Usage
new Foo {
def foo(a: T) = {
println("Foo")
a
}
}
Can I still use a companion object, i.e. can I apply generic type parameters to a function, rather than a method or class?

Yes you can do this by emulating rank 2 polymorphism. Based on this article you can do:
trait ~>[F[_],G[_]] {
def apply[A](a: F[A]): G[A]
}
type Id[A] = A
abstract class Foo {
def foo[T](a: T): T
}
object Foo {
def apply(f: Id ~> Id) = new Foo {
def foo[T](a: T): T = f(a)
}
}
val fun = new (Id ~> Id) { def apply[T](a: T): T = { println("Foo"); a } }
val foo = Foo(fun)
foo.foo(1)
foo.foo("String")

Related

Scala, override method on generic type

I am trying to build a DSL, one of the method on this DSL is parameterless and use a bounded generic type. Today I have to add a "feature" that will ideally use the same method name. However, because the only parameter is the generic one, I cannot override it with the usual way.
Is there a trick to allow the use of the same method for different generic types ?
My method looks like:
def ask[H <: Handler] = {
new CommandBuilder[H]
}
class CommandBuilder[H <: Handler] {
def toExecute[C <: H#C](command: C) = {
//...
}
}
And I would like to add:
def ask[S <: State] = {
new QueryBuilder[S]
}
class QueryBuilder[S <: State] {
def toExecute[Q <: S#Q](query: Q) = {
//...
}
}
I was thinking to pattern match a ClassTag on the type but I need strong type safety:
Query on a Handler, is not allowed. ask[State] must return QueryBuilder
Command and Query are the only supported types. The generic type of ask can only be a Handler or a State.
Maybe you could refactor your code to something like this?
sealed trait FooBar
sealed trait Foo extends FooBar {
def process(i: Int): Int
}
object Foo {
implicit final case object FooImpl extends Foo {
override def process(i: Int): Int = i + 1
}
}
sealed trait Bar extends FooBar {
def process(s: String): String
}
object Bar {
implicit final case object BarImpl extends Bar {
override def process(s: String): String = s.toUpperCase
}
}
object Test {
trait FooBarPartiallyApplied[FB <: FooBar] {
type Out
def out: Out
}
object FooBarPartiallyApplied {
type Aux[FB <: FooBar, _Out] = FooBarPartiallyApplied[FB] { type Out = _Out }
implicit final def FooPartiallyAppliedBuilder[F <: Foo]: Aux[F, FooPartiallyApplied[F]] =
new FooBarPartiallyApplied[F] {
override final type Out = FooPartiallyApplied[F]
override final val out: FooPartiallyApplied[F] =
new FooPartiallyApplied[F](dummy = true)
}
implicit final def BarPartiallyAppliedBuilder[B <: Bar]: Aux[B, BarPartiallyApplied[B]] =
new FooBarPartiallyApplied[B] {
override final type Out = BarPartiallyApplied[B]
override final val out: BarPartiallyApplied[B] =
new BarPartiallyApplied[B](dummy = true)
}
final class FooPartiallyApplied[F <: Foo](private val dummy: Boolean) extends AnyVal {
def toExecute(i: Int)(implicit foo: F): Int = foo.process(i)
}
final class BarPartiallyApplied[B <: Bar](private val dummy: Boolean) extends AnyVal {
def toExecute(s: String)(implicit bar: B): String = bar.process(s)
}
}
def ask[FB <: FooBar](implicit pa: FooBarPartiallyApplied[FB]): pa.Out =
pa.out
}
It works as expected:
Test.ask[Foo.FooImpl.type].toExecute(10)
// res: Int = 11
Test.ask[Foo.FooImpl.type].toExecute("blah")
// Type error.
Test.ask[Bar.BarImpl.type].toExecute(10)
// Type error.
Test.ask[Bar.BarImpl.type].toExecute("blah")
// res: String = "BLAH"

How to make implicits available to inner function

I would like to define implicit value in a wrapper function and make it available to inner function, so far I managed to do that by passing implicit variable from wrapper:
case class B()
trait Helper {
def withImplicit[A]()(block: => A): A = {
implicit val b: B = B()
block
}
}
class Test extends Helper {
def useImplicit()(implicit b: B): Unit = {...}
def test = {
withImplicit() { implicit b: B =>
useImplicit()
}
}
}
Is it possible to avoid implicit b: B => and make implicit val b: B = B() available to inner function block?
This will be possible in Scala 3 with implicit function types (keyword given is instead of implicit)
case class B()
trait Helper {
def withImplicit[A]()(block: (given B) => A): A = {
given B = B()
block
}
}
class Test extends Helper {
def useImplicit()(given b: B): Unit = {}
def test = {
withImplicit() {
useImplicit()
}
}
}
https://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html
https://dotty.epfl.ch/blog/2016/12/05/implicit-function-types.html

Import does not bring implicits in scope

I am facing an error about unreachable implicits in scope:
Error:(38, 68) could not find implicit value for parameter strategy: XXX.NeoStrategy[T]
(summoner: Summoner, v: String) => summoner.summonEvaluation[T](v)
I implement the answer of Tim to that question : https://stackoverflow.com/a/56668734/3896166
I tried to import the implicit object Strategies within TypeTable scope with :
import XXX.NeoStrategies._
but to no success.
The followings are each file of the base logic I want to use:
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
trait NeoStrategy[T <: Type_top] {
def evaluate(v: String, helper: Helper): Int
}
object NeoStrategies {
implicit object NeoStrategy_A extends NeoStrategy[Type_A] {
def evaluate(v: String, helper: Helper): Int = 1
}
implicit object NeoStrategy_B extends NeoStrategy[Type_B] {
def evaluate(v: String, helper: Helper): Int = 2
}
}
case class Helper(name: String) {
def summonEvaluation[T <: Type_top](v: String)(implicit strategy: NeoStrategy[T]): Int = {
strategy.evaluate(v, this)
}
}
trait TypeOMap {
protected def computeStuff[T <: Type_top]: (Helper, String) => Int
protected val computeMap: Map[String, (Helper, String) => Int]
}
import XXX.NeoStrategies._
trait TypeTable extends TypeOMap {
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v)
}
override protected val computeMap = Map(
"a" -> computeStuff[Type_A],
"b" -> computeStuff[Type_B]
)
}
class Summoner extends TypeTable {
def callsMapAndEvaluates(typeIdentifier: String, helper: Helper, param: String): Double = {
computeMap(typeIdentifier)(helper, param)
}
}
object StackO {
def main(args: Array[String]): Unit = {
val mySummoner = new Summoner
// mySummoner allows the selecting of a given type with
// its "typeIdentifier" input in combination with the "TypeTable" it extends
val r = mySummoner.callsMapAndEvaluates("a", Helper("make it right"), "I, parameter")
}
}
This is not the first time I use implicits but not with something like the computeMap above. Still, I understand the logic of it, but fail at making it right.
How can I have summoner.summonEvaluation[T](v) find the required implicit?
Just add context bound
override protected def computeStuff[T <: Type_top : NeoStrategy] ...
It seems you want to work with singleton types. In Scala 2.12 + Shapeless
import shapeless.Witness
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux[Witness.`"a"`.T, Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux[Witness.`"b"`.T, Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String](s: Witness.Aux[S])(implicit
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s.value, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
In Scala 2.13
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String with Singleton] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String with Singleton, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String with Singleton, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux["a", Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux["b", Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String with Singleton](s: S)(implicit
value: ValueOf[S],
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
The underlying problem is this:
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v) // implicit for NeoStrategy[T]...?
}
Since summonEvaluation[T] requires an implicit argument of type NeoStrategy[T], this means you must have one in scope for any T that's a subclass of Type_top. However, NeoStrategies only provides two instances: one for Type_A and Type_B. This is not enough for the compiler. Understandably so - for instance, you haven't provided any NeoStrategy for
Type_top itself
subclasses of Type_A and Type_B (perfectly legal to create)
There are two basic ways you can handle this:
Delaying the implicit resolution
As per the other answer, instead of trying to resolve the implicit inside computeStuff, add a context bound there too. If the point where you have to supply the implicit is only reached when you know what T is, you won't have to provide instances for any possible subtype.
Providing implicits for all possible subtypes
If absolutely you want to keep the implicit resolution inside computeStuff, you're going to have to offer a method
implicit def getNeoStrategy[T <: Type_top] : NeoStrategy[T] = ???
Unfortunately, doing this is probably going to involve a bunch of reflection and potentially runtime errors for edge cases, so I'd recommend the context bound on computeStuff.

How to make method return type covariant

I have a following classes:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager[T <: Foo](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
And of course update function does not compiles:
Type missmatch found Foo required T
How to make def update: Foo covariant?
Looks like you want something like F-bounded polymorphism:
trait Foo[T <: Foo[T]] { self: T =>
def update: T
}
class ConcreteFoo extends Foo[ConcreteFoo] {
override def update = new ConcreteFoo
}
class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
An alternative, and probably simpler, solution is to use an immutable Map, as Luka said. But then there's no need to have type parameters anymore:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager(private var _foos: immutable.Map[String, Foo]) {
def foos = _foos
def update(id: String): Unit = {
_foos = _foos.updated(id, _foos(id).update)
}
}
You could also keep your current solution and remove the type parameter. But then you have the slight inconvenience that you can't pass a mutable.Map[String,ConcreteFoo] to the constructor of FooManager.
I'd suggest going with an immutable Map instead. As only immutable collections can have covariant type parameters.
class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) {
def update(id: String): FooManager[Foo] = {
new FooManager(foos.updated(id, foos(id).update))
}
}

Scala constructor signature

Is it possible to define constructor signature in Scala ?
abstract class A {
def this (s: String): this.type // doesn't work
def this (i: Int): this.type // doesn't work
def this (d: Double): this.type // doesn't work
}
class B(var s: String) extends A {
def this(i: Int) = {
this("int "+i.toString())
}
def this(d: Double) = {
this("double "+d.toString())
}
}
What are you trying to achieve? You can do like this:
abstract class A(i: Int)
case class B(s: String) extends A(s.toInt) {
def this(i: Int) = {
this(i.toString)
}
def this(d: Double) = {
this(d.toString)
}
}
Usage:
B("1")
new B(1)
new B(1.0)
You can't do exactly what you want, as pointed out by other answer, but one approach is to use a factory:
trait Foo {
// methods you need
}
trait FooCompanion[T <: Foo] {
// these methods replace constructors in your example
def apply(s: String): T
def apply(i: Int): T
...
}
Implementation:
class Bar(s: String) extends Foo {
...
}
object Bar extends FooCompanion[Bar] {
def apply(s: String) = new Bar(s)
...
}
and you can have methods taking FooCompanion. This pattern is used e.g. in the Scala collections library.
No that is not possible. Constructors are special: You need to write new X() instead of X(), and there is no polymorphic dispatch, e.g. you cannot do def test[A]() = new A(). So there is no scenario in which an abstract constructor would make any sense.