Abstract Over TypeClass - scala

Starting with some simple code:
trait Moveable[A] {
def move(a: A): A
}
trait Animal {
def kick[A <: Animal: Moveable](a: A): A = implicitly[Moveable[A]] move a
}
object Cat {
implicit object CatMoveable extends Moveable[Cat] {
def move(cat: Cat): Cat = cat copy (pos = cat.pos + 4)
}
}
case class Cat(pos: Int) extends Animal
case class Dog(pos: Int) extends Animal
val someAnimal: Animal = Dog(0)
val kickedCat: Cat = someAnimal kick Cat(0)
println(kickedCat) // Cat(4)
I decided to distinguish between, let´s say, Quadruped and Biped animals:
trait FourFeetMoveable[A] {
def moveWithFourFeets(a: A): A
}
trait TwoFeetMoveable[A] {
def moveWithTwoFeets(a: A): A
}
trait Animal {
def kick[A <: Animal /*: ??? */](a: A): A
}
trait Quadruped extends Animal {
def kick[A <: Animal: FourFeetMoveable](a: A): A = implicitly[FourFeetMoveable[A]] moveWithFourFeets a
}
trait Biped extends Animal {
def kick[A <: Animal: TwoFeetMoveable](a: A): A = implicitly[TwoFeetMoveable[A]] moveWithTwoFeets a
}
object Chicken {
implicit object ChickenTwoFeetMoveable extends TwoFeetMoveable[Chicken] {
def moveWithTwoFeets(chicken: Chicken): Chicken = chicken copy (pos = chicken.pos + 2)
}
}
case class Dog(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped
val someAnimal: Animal = Dog(0)
val kickedChicken: Chicken = someAnimal kick Chicken(0)
println(kickedChicken) // Chicken(2)
A must have is to have two totally different typeclasses FourFeetMoveable and TwoFeetMoveable, so I can´t abstract over them with something like this:
trait Moveable[A] {
def move(a: A): A
}
So how can I abstract over the typeclasses used as a context bound at method kick in trait Animal(see the ???)?
EDIT
Sorry, I should have made my example clearer. Lets say the effect of being kicked can be some movement or some other action. I wanted to abstract over that effect with a typeclass.
In the following code I am showing what I mean and also used an abstract type member KickingEffect to abstract over the required typeclass, as 0__ proposed:
trait StumbleEffect[A <: Animal] {
def stumble(a: A): A
}
trait GlideEffect[A <: Animal] {
def glide(a: A): A
}
trait Animal {
type KickingEffect[A <: Animal]
def kick[A <: Animal: KickingEffect](a: A): A
}
trait Biped extends Animal {
type KickingEffect[A <: Animal] = StumbleEffect[A]
override def kick[A <: Animal: StumbleEffect](a: A): A = implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
type KickingEffect[A <: Animal] = GlideEffect[A]
override def kick[A <: Animal: GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}
object Dog {
implicit object DogGlideEffect extends GlideEffect[Dog] {
def glide(dog: Dog): Dog = dog copy (pos = dog.pos + 4)
}
}
case class Dog(pos: Int) extends Quadruped
case class Cat(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped
But then I ran into another problem, when it comes to sequences of animals:
type Beast[A <: Animal, KE[_ <: Animal]] = A { type KickingEffect[X <: Animal] = KE[X] }
val dogBeast: Beast[Dog, GlideEffect] = Dog(0) // fine
type GlideBeasts[A <: Quadruped] = Beast[A, GlideEffect]
val glideBeasts: Seq[GlideBeasts[Quadruped]] = Seq(Dog(0), Cat(0)) // fine
def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](kicker: Beast[A, KE])(animals: Seq[KA])(implicit ev: kicker.KickingEffect[KA]): Seq[KA] = {
for (a <- animals) yield kicker kick a
}
val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // wrong inferred kinds of type arguments
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // missing implicit evidence

Like this?
trait Moveable[A] {
def move(a: A): A
}
trait FourFeetMoveable[A] extends Moveable[A]
trait TwoFeetMoveable[A] extends Moveable[A]
trait Animal {
type CanKick[A] <: Moveable[A]
def kick[A <: Animal : CanKick](a: A): A = implicitly[CanKick[A]] move a
}
trait Quadruped extends Animal {
type CanKick[A] = FourFeetMoveable[A]
}
trait Biped extends Animal {
type CanKick[A] = TwoFeetMoveable[A]
}
Regarding your edit: I would recommend at this point not to further try to model that with types, unless it is really an extremely crucial point in your application or a pure thought experiment. You can get easily overambitious with type-safe design, then the ratio between design effort and application value is getting to big; I would just drop some compile-time safety and go for pattern matching and runtime errors.
If you do want to follow the types route, as soon as you have collections, you will need something like HLists to preserve the individual types of the collection members.
Anyway, you can make your example work (with explicit type parameters):
def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](
kicker: Beast[A, KE])(animals: Seq[KA])(implicit effect: KE[KA]): Seq[KA] = {
for (a <- animals) yield kicker kick a
}
val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // still doesn't figure out the types
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // ok!
As said, the tricky or impossible part comes when you try to do this with heterogeneous lists (e.g. requiring different effects). You might get away with using a helper type class for the elements of the sequence, instead, so that implicits can be resolved per item before.

As a side note, I found it always useful to not introduce type bounds till the moment they are really needed. Not only do you safe a lot of typing (no pun intended), but you keep options open (e.g. for later variance annotations). The following is totally sufficient:
trait StumbleEffect[A] {
def stumble(a: A): A
}
trait GlideEffect[A] {
def glide(a: A): A
}
trait Animal {
type KickingEffect[A]
def kick[A : KickingEffect](a: A): A
}
trait Biped extends Animal {
type KickingEffect[A] = StumbleEffect[A]
override def kick[A : StumbleEffect](a: A): A =
implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
type KickingEffect[A] = GlideEffect[A]
override def kick[A : GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}
etc.

Related

Aux-like pattern for path dependent types?

Goal: I would like to write
feedImplicitInstance[Cat](new CatFood())`
and have the same effect as
feedExplicitInstance(Cat.CatInstance)(new CatFood())
How can I do that ?
Is it possible to do that at all ?
This is what I tried (but it did not really work):
object DepType extends App{
println("bla")
def feedExplicitInstance[AnimalInstance]
(animal:AnimalTypeClass[AnimalInstance])(food:animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
// Does not compile:
def feedImplicitInstance[AnimalInstance,Food](food:Food)
(implicit animal:AnimalTypeClass[AnimalInstance],aux:Cat.Aux[Food,AnimalInstance]) = {
animal.feed(food)
// Error:(17, 17) type mismatch;
// found : food.type (with underlying type Food)
// required: animal.FoodThatAnimalLikes
// animal.feed(food)
}
feedExplicitInstance(Cat.CatInstance)(new CatFood())
}
trait Food{
def eat():Unit
}
trait AnimalTypeClass [AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f:FoodThatAnimalLikes)=f.eat()
}
trait Cat
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
object Cat {
type Aux[Food,Animal]= AnimalTypeClass[Animal] {type FoodThatAnimalLikes = Food}
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
First of all, it makes more sense to put Aux in the AnimalTypeClass companion object, and switch the order of its type parameters. Though none of this is required to make it compile.
In order to enable your preferred calling convention of feedImplicitInstance[Cat](new CatFood()) feedImplicitInstance is allowed to have only one type parameter. But Food must be a type parameter because forward references like animal.FoodThatAnimalLikes in parameter lists are not allowed, as you probably noticed yourself. That's why you needed the Aux in the first place. To reconcile those conflicting constraints, you should manually implement a sort of type parameter currying. That's what the Feeder class in the following complete example is for:
object DepType extends App {
def feedExplicitInstance[AnimalInstance]
(animal: AnimalTypeClass[AnimalInstance])(food: animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
class Feeder[AnimalInstance] {
def apply[F <: Food](food: F)(implicit animal: AnimalTypeClass.Aux[AnimalInstance, F]) =
animal.feed(food)
}
def feedImplicitInstance[AnimalInstance] = new Feeder[AnimalInstance]
feedExplicitInstance(Cat.CatInstance)(new CatFood())
feedImplicitInstance[Cat](new CatFood())
}
trait Food{
def eat(): Unit
}
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
trait AnimalTypeClass[AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f: FoodThatAnimalLikes) = f.eat()
}
object AnimalTypeClass {
type Aux[A, F <: Food]= AnimalTypeClass[A] {type FoodThatAnimalLikes = F}
}
trait Cat
object Cat {
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
If we define Aux like this:
object AnimalTypeClass {
type Aux[A, F] = AnimalTypeClass[A] { type FoodThatAnimalLikes = F }
implicit object CatInstance extends AnimalTypeClass[Cat] {
override type FoodThatAnimalLikes = CatFood
}
}
We can then summon the right implicit typeclass via a method:
def feed[A, F <: Food](f: F)(implicit animalTypeClass: AnimalTypeClass.Aux[A, F]) = {
animalTypeClass.feed(f)
}
And now this compiles and runs:
feed(new CatFood())
I changed the name of the generic type parameters a bit, but they're largely the same as in your example. Just note the implicit instance definition changes.
Using Yuval's answer, this is how my modified code looks like:
object DepType2 extends App{
println("bla")
def feedExplicitInstance[AnimalInstance]
(animal:AnimalTypeClass[AnimalInstance])(food:animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
def feedImplicitInstance[AnimalInstance,Food](food:Food)
(implicit animal:AnimalTypeClass[AnimalInstance],aux:AnimalTypeClass.Aux[Food,AnimalInstance]) = {
aux.feed(food)
}
feedExplicitInstance(AnimalTypeClass.CatInstance)(new CatFood())
feedImplicitInstance(new CatFood())
}
trait Food{
def eat():Unit
}
trait AnimalTypeClass [AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f:FoodThatAnimalLikes)=f.eat()
}
trait Cat
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
object AnimalTypeClass {
type Aux[Food,Animal]= AnimalTypeClass[Animal] {type FoodThatAnimalLikes = Food}
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
So I had to change animal to aux in feedImplicitInstance and object Cat into object AnimalTypeClass and now everything works fine.
Of course the original question was a little bit trickier:
How can I write feedImplicitInstance[Cat](new CatFood()) ?
Jasper's answer is the answer for the original question. I have not understood his answer yet perfectly - I need to find some time to read carefully, hopefully very soon.

Ensure instance of typeclass

if I have an ADT and a type class, is there a way for me to ensure at compile time that there is an instance of the type class for every subtype of the ADT?
Just to give an example - I'd really like this to not compile as there isn't an instance of A for Baz
sealed trait Foo
final case class Bar(s: String) extends Foo
final case class Baz(i: Int) extends Foo
trait A[T <: Foo] {
type O
def f(t: T): O
}
implicit val barA = new A[Bar] {
type O = String
def f(t: Bar): O = t.s
}
This is all my own code, so I'm happy to change the encoding of Foo if required (maybe a shapeless coproduct can help me out here?)
EDIT
Sorry, should have mentioned - I have a function a bit like this I'd like to implement (lets assume my instances are in an object I've imported and they are the only implementations in scope)
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From the comments below, it looks like I should also have said that the thing that calls g can do so with a List of any subclass of Foo (I have no control over that part other than to change g I guess). Here, I'm trying to ensure that if someone changes Foo later on, then there will be a compiler error letting the user know that they need to implement an appropriate A
You can use F-bounded polymorphism (aka Curiously Recurrent Template Pattern):
sealed abstract class Foo[Self <: Foo](implicit val hasA: A[Self])
final case class Bar(s: String) extends Foo[Bar]
final case class Baz(i: Int) extends Foo[Baz]
abstract class is used instead of trait so the implicit is picked up automatically.
However, for this specific A and g, you may not really need a type class:
sealed trait Foo[O] {
def f(): O
}
final case class Bar(s: String) extends Foo[String] {
def f() = s
}
def g(fs: List[Foo[O]]): List[O] = fs.map(_.f())
trait Foo[T] {
this: ImplementThis[T] =>
}
case class Bar() extends Foo[String] with ImplementThis[String] {
override def f(t: String): String = {
t
}
}
case class Baz() extends Foo[Int] with ImplementThis[Int] {
override def f(t: Int): Int = {
t
}
}
trait ImplementThis[T] {
type O
def f(t: T): O
}
Try something like this. This will enforce implementation of def f(t: T):O for any subclass of Foo that's defined.
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From this, I assume you want all the child classes of your Foo to have a def f so that they dont fail at runtime. I think my above suggestion will enforce that def f implementation and solve this problem.

Scala Mutually Convertible Generic Types

I'm very new to Scala programming, and I really like the degree to which code is composable. I wanted to write some traits that deal with two related objects that are convertible to each other, and build more functionality by continuing to extend that trait so that when I create objects I can specify the related types for my generics. Here is a working toy example of the type of code I'm talking about:
trait FirstConverter[First] {
def toFirst: First
}
trait SecondConverter[Second] {
def toSecond: Second
}
trait TwoWayConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] {
def firstToSecond(x: First) = x.toSecond
def secondToFirst(x: Second) = x.toFirst
}
trait RoundTripConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] extends TwoWayConverter[First, Second] {
def firstToFirst(x: First) = secondToFirst(firstToSecond(x))
def secondToSecond(x: Second) = firstToSecond(secondToFirst(x))
}
case class A(s: String) extends SecondConverter[B] {
def toSecond: B = B((s.toInt) + 1)
}
case class B(i: Int) extends FirstConverter[A] {
def toFirst: A = A((i * 2).toString)
}
object ABConverter extends RoundTripConverter[A, B]
object Main {
def main(args: Array[String]): Unit = {
println(ABConverter firstToSecond A("10")) // 11
println(ABConverter secondToFirst B(42)) // 84
println(ABConverter firstToFirst A("1")) // 4
println(ABConverter secondToSecond B(2)) // 5
}
}
While this works, I'm not sure if it's idiomatic Scala. I'm asking if there are any tricks to make the type definitions more concise and if I can somehow define the type restrictions only once and have them used by multiple traits which extend other traits.
Thanks in advance!
One way to improve your design would be to use a type class instead of inheriting from FirstConverter and SecondConverter. That way you could use multiple conversion functions for the same types and convert between classes you don't control yourself.
One way would be to create a type class which can convert an A into a B :
trait Converter[A, B] {
def convert(a: A): B
}
trait TwoWayConverter[A, B] {
def firstToSecond(a: A)(implicit conv: Converter[A, B]): B = conv.convert(a)
def secondToFirst(b: B)(implicit conv: Converter[B, A]): A = conv.convert(b)
}
trait RoundTripConverter[A, B] extends TwoWayConverter[A, B] {
def firstToFirst(a: A)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
secondToFirst(firstToSecond(a))
def secondToSecond(b: B)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
firstToSecond(secondToFirst(b))
}
We could create type class instances for the following two classes Foo and Bar similar to your A and B
case class Foo(s: String)
case class Bar(i: Int)
implicit val convFooBarFoor = new Converter[Foo, Bar] {
def convert(foo: Foo) = Bar((foo.s toInt) + 1)
}
implicit val convBarFoo = new Converter[Bar, Foo] {
def convert(bar: Bar) = Foo((bar.i * 2) toString)
}
We then could create a FooBarConverter :
object FooBarConverter extends RoundTripConverter[Foo, Bar]
FooBarConverter firstToSecond Foo("10") // Bar(11)
FooBarConverter secondToFirst Bar(42) // Foo(84)
FooBarConverter firstToFirst Foo("1") // Foo(4)
FooBarConverter secondToSecond Bar(2) // Bar(5)
The only problem is because we can not pass parameters to a trait, we can not limit the types to types with a Converter type class instance. So you can create the StringIntConverter below even if no Converter[String, Int] and/or Convert[Int, String] instances exist.
object StringIntConverter extends TwoWayConverter[String, Int]
You cannot call StringIntConverter.firstToSecond("a") because the firstToSecond method needs the implicit evidence of the two mentioned type class instances.

How to remove repetitive case statements for implementations of a sealed trait

I often find that I need to extract the type of a sealed trait before doing the same thing to each implementation:
sealed trait Trait
case class Foo() extends Trait
case class Bar() extends Trait
// ... lots of other implementations
// *must* take a `Trait`, not a `T <: Trait`
def thing(t: Trait): ??? = t match {
case f: Foo => // something with the instance and specific type
case b: Bar => // something with the instance and specific type
// ... same thing again for other implementations
}
for example
// typically provided by somebody else...
trait Thing[T] { def thingy: String }
implicit def thing[T]: Thing[T] = new Thing[T] { def thingy = "stuff" }
def thing(t: Trait): String = t match {
case Foo() => implicitly[Thing[Foo]].thingy
case Bar() => implicitly[Thing[Bar]].thingy
// ...
}
I'd like to reduce the boilerplate involved in doing this.
UPDATE: nowadays we'd use typeclass derivation via shapeless. e.g. https://github.com/fommil/shapeless-for-mortals
It turns out that you can use shapeless' polymorphic functions and co-product to do this:
object thing extends Poly1 {
implicit def action[T <: Trait: Thing] = at[T](
a => implicitly[Thing[T]].thingy
)
// magic that makes it work at the sealed trait level
def apply(t: Trait): String =
Generic[Trait].to(t).map(thing).unify
}
which can then be used like
println(thing(Foo(): Trait))
I'd like to make this easier to write via an abstract class (let's forget about passing on implicit parameters to action for now), e.g.
abstract class MatchSealed[In, Out] extends Poly1 {
implicit def poly[T <: In] = at[T](action)
def action[T <: In](t: T): Out
import ops.coproduct.Mapper
def apply[R <: HList](in: In)(
implicit
g: Generic.Aux[In, R],
m: Mapper[this.type, R]
): Out = {
val self: this.type = this
g.to(in).map(self).unify
}
}
but this is failing with a missing Mapper[self.type, g.Repr] on the final line. I don't know which implicit is missing, but I suspect it is the self.type. I really want to capture realisedSelf.type but I don't know how to do that.
UPDATE: it turns out that it is not possible to obtain the Mapper because it needs access to the realised object Unable to map on HList

Overriding higher-kinded abstract types in Scala

The following code shows a shallow hierarchy where a type representing a generic binary operation is used to substantiate a parameterized abstract type in another shallow container hierarchy:
trait BinaryOp[A] extends ((A,A) => A)
trait Plus[A] extends BinaryOp[A]
trait Minus[A] extends BinaryOp[A]
trait BaseOps {
type T[A] <: BinaryOp[A]
def apply[B](one: B, two: B)(op: T[B]) = op(one, two)
}
case object PlusOp extends BaseOps {
override type T[A] = Plus[A]
}
case object MinusOp extends BaseOps {
override type T[A] = Minus[A]
}
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The idea is to be able to state an operation that may be valid for many different types up front, without being tied to a type-specific operation. If I define an expression class generically, all is well
case class Expr[T <: BaseOps](bo: T = PlusOp)
However for my use case it is undesirable for Expr to to be paremeterized:
case class Expr(bo: BaseOps = PlusOp)
The following code fails without a generic Expr:
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The error:
found : App.plus.type (with underlying type java.lang.Object with Plus[Int])
required: exp.bo.T[Int]
exp.bo(1,2)(plus)
This makes it seem as if the type information from the abstract type T[A] <: BinaryOp[A] is not being substantiated with the information in the subtype PlusOp, which overrides the abstract type as T[A] = Plus[A]. Is there any way to work around this without making Expr generic?
With "-Ydependent-method-types",
def Expr(_bo: BaseOps = PlusOp) = new BaseOps {
override type T[A] = _bo.T[A]
val bo: _bo.type = _bo
}
But, I don't know what this precisely means...