How to substitute generic anonymous functions? - scala

Suppose there is a trait for legged animals:
trait Legged {
val legs: Int
def updateLegs(legs: Int): Legged
}
And there two such legged animals:
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
There is also a holder for these animal, in a farm
case class Farm(chicken: Chicken, dog: Dog)
And a generic method to mutate all the legged animals by adding them one extra leg
def mutate(legged: Legged): Legged = legged.updateLegs(legged.legs + 1)
The question is how to implement a method on the Farm so that it takes the mutate: Legged => Legged function as a parameter and applies it to all the Legged animals?
val farm = Farm(Chicken(1500), Dog("Max"))
farm.mapAll(mutate) //this should return a farm whose animals have an extra leg
What I've come with thus far, but it doesn't actually work
trait LeggedFunc[T <: Legged] extends (T => T)
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc[Legged]): Farm = {
//todo how to implement?
val c = leggedFunc[Chicken](chicken)
}
}
I know how to do it with patter matching, but that leads to potential MatchError.

A possible way to do that (type-safely, without using asInstanceOf) could be using object-dependant type.
First of all, we should add an abstract member that uses the concrete type of Legged subclasses:
sealed trait Legged { self =>
type Me >: self.type <: Legged // F-Bounded like type, Me have to be the same type of the subclasses
val legs: Int
def updateLegs(legs: Int): Me
}
Then, the Legged subclasses became:
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
type Me = Chicken
override def updateLegs(legs: Int): Chicken = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
type Me = Dog
override def updateLegs(legs: Int): Dog = copy(legs = legs)
}
In this way, it is possible to define a function that returns the concrete subclass of the Legged passed (similar to what #Gaƫl J done):
trait LeggedFunc {
def apply(a : Legged): a.Me
}
val mutate = new LeggedFunc { override def apply(legged: Legged): legged.Me = legged.updateLegs(legged.legs + 1) }
Finally, the Farm class is straightforward defined as:
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc): Farm = {
val c : Chicken = leggedFunc(chicken)
val d : Dog = leggedFunc(dog)
Farm(c, d)
}
}
Scastie for Scala 2
But why object-dependent type?
In Scala 3.0, it is possible to define dependent function type as:
type LeggedFunc = (l: Legged) => l.Me
val mutate: LeggedFunc = (l) => l.updateLegs(l.legs + 1)
Making this solution (object-dependent type) cleaner and type-safe.
Scastie for Scala 3 version

I'll just add to #gianlucaaguzzi's answer that in Scala 2 dependent/polymorphic functions can be emulated with Shapeless
import shapeless.ops.hlist.Mapper
import shapeless.{Generic, HList, Poly1}
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll[L <: HList](mutate: Poly1)(implicit
generic: Generic.Aux[Farm, L],
mapper: Mapper.Aux[mutate.type, L, L]
): Farm = generic.from(mapper(generic.to(this)))
}
object mutate extends Poly1 {
implicit def cse[T <: Legged]: Case.Aux[T, T#Me] =
at(legged => legged.updateLegs(legged.legs + 1))
}
val farm = Farm(Chicken(1500), Dog("Max"))
println(farm.mapAll(mutate)) // Farm(Chicken(1500,3),Dog(Max,5))

This can be done using the method asInstanceOf
trait Legged {
val legs: Int
def updateLegs(legs: Int): Legged
}
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Dog(name: String, legs: Int = 4) extends Legged {
override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
case class Farm(chicken: Chicken, dog: Dog){
def mapAll(leggedFunc: (Legged) => Legged): Farm = {
copy(
leggedFunc(chicken.asInstanceOf[Legged]).asInstanceOf[Chicken],
leggedFunc(dog.asInstanceOf[Legged]).asInstanceOf[Dog]
)
}
}
def mutate(legged: Legged): Legged = legged.updateLegs(legged.legs + 1)
val farm = Farm(Chicken(1500), Dog("Max"))
println (farm.mapAll(mutate)) // prints: Farm(Chicken(1500,3),Dog(Max,5))
Try it on scastie.
Update: This is an alternative implementation more similar to your own code:
trait LeggedFunc[T <: Legged] extends (T => T)
case class Farm(chicken: Chicken, dog: Dog) {
def mapAll(leggedFunc: LeggedFunc[ Legged]): Farm = {
val c = leggedFunc(chicken).asInstanceOf[Chicken]
val d = leggedFunc(dog).asInstanceOf[Dog]
copy (c, d)
}
}
Try it on scastie.

I think you'd avoid most of the issues you encounter by having a truly generic mutate method (with a type parameter):
def mutate[T <: Legged](legged: T): T = legged.updateLegs(legged.legs + 1)
Then, when applied to a Chicken it will return back a Chicken, and same goes for Dog.

Related

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.

Scala typed trait different types Implementation keeping it in Map, not working

Is there any better design to achieve this scenario?
case class Animal()
case class Dog() extends Animal
case class Cow() extends Animal
trait BasePropertyImpl[T <: Animal] {
def property1(animal: T): T
def property2(animal: T): T
}
object DogPropertyImpl extends BasePropertyImpl[Dog] {
def property1(animal: Dog): Dog = ???
def property2(animal: Dog): Dog = ???
}
object CowPropertyImpl extends BasePropertyImpl[Cow] {
def property1(animal: Cow): Cow = ???
def property2(animal: Cow): Cow = ???
}
object AnimalImplRegistrar {
def getRegisteredAnimals: Map[String, BasePropertyImpl[Animal]] = Map(
"Dog" -> DogPropertyImpl,
"Cow" -> CowPropertyImpl,
)
}
object Main {
def main(args: Array[String]): Unit = {
val animal = AnimalImplRegistrar.getRegisteredAnimals.get("Dog").get
aminal.property1(Dog())
}
}
Here what I am trying to achieve is deferent implementation say CowPropertyImpl, DogPropertyImpl , or some more different implementations, I am keeping it in a Map and in runtime based on user input I am retrieving the implementation from Map and calling the method of that Impl class
This is a good candidate for the Type Class Pattern:
sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal
trait AnimalProperties[A] {
def property: A
}
object AnimalProperties {
implicit val dogProperties = new AnimalProperties[Dog.type] {
override def property: Dog.type = ???
}
implicit val catProperties = new AnimalProperties[Cat.type] {
override def property: Cat.type = ???
}
}
def f[A](a: A)(implicit ev: AnimalProperties[A]) = {
val a: A = ev.property
}
Based on the type of A (cat, dog) we get the desired properties of each animal.

Scala - Extends multi class with parameters

I would like to make some classes like this.
class A(val a1: String) {
def message() = println(a1)
}
class B(val b1: String) {
def doB() = println(b1)
}
class C(val c1: String) {
def something() = println(c1)
}
class AB(val a: String, val b: String) extends A(a) with B(b) {
// ^error
}
class AC..
class BC..
I tried to use trait but since trait cannot have any parameter, It made error too. How should I do to make somthing like this.
It gives you error because trait doesn't have constructor. But you can change it to the trait parameters like this;
class A(val a1: String) {
def message() = println(a1)
}
trait B {
def b: String
def doB() = println(b)
}
class AB(val a: String, val b: String) extends A(a) with B {
//this should work
}

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.

creating a new instance of a type in scala

If I have a class C defined as
class C[A]
is there any way to create a new instance of A within C? Something like
class C[A] {
def f(): A = new A()
}
I understand that, if this were possible, you'd probably have to specify the constructor arguments somewhere, and that's fine.
If it's not possible, are there any design patterns for dealing with the sort of situation where you'd like to create a new instance of a type?
You could use a type class to abstract instantiation:
trait Makeable[T] {
def make: T
}
class C[T: Makeable] {
def f(): T = implicitly[Makeable[T]].make
}
For example,
implicit object StringIsMakeable extends Makeable[String] {
def make: String = "a string"
}
val c = new C[String]
c.f // == "a string"
When you instantiate C, you'll need to provide, explicitly or implicitly, a Makeable that will act as a factory of the appropriate type. That factory, of course, would be responsible for supplying any constructor arguments when it invokes the constructor.
Alternatively, you could use a Manifest, but be warned that this approach relies on reflection and is not type safe:
class C[T: Manifest] {
def f(): T = manifest[T].erasure.newInstance.asInstanceOf[T]
}
For completeness, you can also easily extend this approach to pass some or all of the constructor parameters in to the make method:
trait Makeable[Args, T] { def make(a: Args): T }
class C[Args, T](implicit e: Makeable[Args, T]) {
def f(a: Args): T = e.make(a)
}
// some examples
case class Person(firstName: String, lastName: String)
implicit val personFactory1 = new Makeable[(String, String), Person] {
def make(a: (String, String)): Person = Person(a._1, a._2)
}
implicit val personFactory2 = new Makeable[String, Person] {
def make(a: String): Person = Person(a, "Smith")
}
val c1 = new C[String, Person]
c1.f("Joe") // returns Person("Joe", "Smith")
val c2 = new C[(String, String), Person]
c2.f("John", "Smith") // returns Person("John", "Smith")
You can demand an implicit parameter, like so:
class A[T](implicit newT : T) {
val t = newT
}
All you need then is to have an implicit factory of the desired type in scope when you instanciate A, e.g. the following works:
implicit def newSeq[T] = Seq[T]()
val a = new A[Seq[String]]
As shown by:
scala> a.t
res22: Seq[String] = List()
The same as #Raphael's answer with a case class's apply method:
class Container[A](contained: A)
case class Person(name: String)
case class PersonContainer(person: Person) extends Container[Person](person)
implicit def _ = PersonContainer.apply _
class Creator {
def deserializeAndPackage[A, B <: Container[A]](data: Array[Byte])
(implicit containerCreator: (A => B)): B = {
val p = /* deserialize data as type of A */
containerCreator(p)
}
}