Resolve implicit parameter from super type - scala

Is it possible to resolve an implicit parameter for a type B if an implicit is defined for its super type A?
Here is an example :
I have an Enumerable typeclass :
trait Enumerable[A] {
def name(a: A): String
def list: List[A]
//... other methods
}
object Enumeration {
def name[A, T >: A](a: A)(implicit ev: Enumerable[T]) = ev.name(a)
def list[T](implicit ev: Enumerable[T]) = ev.list
// ...
}
Then I define an instance of enumerable :
sealed trait Season
case object Winter extends Season
case object Spring extends Season
case object Summer extends Season
case object Fall extends Season
implicit val seasonEnumerable = new Enumerable[Season] {
override def list: List[Season] = List(Winter, Spring, Summer, Fall)
}
// working :
Enumeration.name(Winter: Season) shouldBe "winter"
// faling :
Enumeration.name(Winter) shouldBe "winter"
Enumeration.name(Winter) is failing if I don't tell scalac that Winter is a Season. I've specified that the implicit parameter in the 'name' method signature is a supertype of A, but it's not sufficient...
Is there a better way to do this?

Eduardo's answer explains why the version with [A, T >: A] doesn't work. But there is a simpler solution to the problem than he gives: instead of introducing T infer as a type parameter, introduce it by an existential type:
def name[A](a: A)(implicit ev: Enumerable[T >: A] forSome { type T }) = ev.name(a)
Or, using a shorthand,
def name[A](a: A)(implicit ev: Enumerable[_ >: A]) = ev.name(a)
Then the compiler only has to decide what T is when looking for ev.

This is a common inconvenience whenever you need type-dependent types to be inferred. Your method
def name[A, T >: A](a: A)(implicit ev: Enumerable[T])
when called on Winter, first A will be inferred to Winter.type and then T to be A, as it conforms to that bound and there are no more constraints on it at that point. Then of course the compiler won't find an instance of Enumerable[Winter.type].
There's an easy solution with type members though:
trait AnyEnumerable {
type E
def name[A <: E](a: A): String
def list: List[E]
}
object Enumeration {
def name[A](a: A)(implicit ev: AnyEnumerable { type E >: A }) = ev.name(a)
def list[T](implicit ev: AnyEnumerable { type E = T }) = ev.list
// ...
}
// an implicit for `Season`
implicit val seasonEnumerable: AnyEnumerable { type E = Season } =
new AnyEnumerable {
type E = Season
def name[A <: Season](a: A): String = a.toString
def list: List[Season] = List(Winter, Spring, Summer, Fall)
}
// compiles!
val zzz = Enumeration.name(Winter)

Related

Scala add extension method when the type params have a common type

I have a type Foo[+A, +B] and a type Bar[+B]. I want to add extension method bar to Foo like this
implicit class FooSyntax[A](foo: Foo[A, Bar[A]]) {
def bar: A = ???
}
So the extension method is only applicable when B is a Bar[A]. And thus all of the following should compile —
trait Fruit
trait Apple extends Fruit
trait Banana extends Fruit
def foo0: Foo[Apple, Bar[Banana]] = ???
def foo1: Foo[Apple, Bar[String]] = ???
def foo2: Foo[Apple, Bar[Apple]] = ???
def foo3: Foo[Apple, List[Apple]] = ???
foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple
For my use-case I want to be able to do this without FooSyntax using an implicit requirement, that way the method is always available and is easy to discover, however calling it is only possible when the type condition is satisfied. This is what I have come so far —
trait Foo[+A, +B] {
def bar[C <: A](implicit evA: A <:< C, evB: B <:< Bar[C]): C
}
Needless to say, this doesn't work.
trait Foo[+A, +B] {
def bar(implicit ev: FooBar[A, B]): ev.Out
}
trait Bar[+B]
trait FooBar[-A, -B] {
type Out
}
object FooBar {
type Aux[A] = FooBar[A, Bar[A]] { type Out = A }
implicit def x[A]: FooBar.Aux[A] =
new FooBar[A, Bar[A]] {
override type Out = A
}
}
All you need to do is remove the type bound from C and just leave the implicit evidence to do its job.
trait Bar[+B]
trait Foo[+A, +B] {
def bar[C](implicit ev1: A <:< C, ev: B <:< Bar[C]): C = ???
}
Then you can do this (as expected):
foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple
You can see the code running here

T <: A, return T method

here is some sample code:
trait A
trait B extends A
def test[T <: A](): T = {
new B {}
}
but I get an compile error:
type mismatch;
found : B
required: T
new B {}
how to make it working ?
( but without doing asInstanceOf[T] at the end )
thanks!
The signature of your method
def test[T <: A](): T
promises that for any type T that is a subtype of A you return a value of this type T. And then you returned a value of type B. You violated the signature (there are many subtypes of A, not only B).
For example you can try a type class (in this way you say that you return a value of T not for any T <: A at all but for any T <: A that can be handled by the type class MakeT)
def test[T <: A]()(implicit makeT: MakeT[T]): T = makeT.makeT()
trait MakeT[T] { // or MakeT[+T]
def makeT(): T
}
object MakeT {
implicit val bMakeT: MakeT[B] = () => new B {}
// or implicit def bMakeT[T >: B]: MakeT[T] = () => new B {}
}
test[B]().isInstanceOf[B] // true
In the situation described by #LuisMiguelMejíaSuárez in his comment
trait C extends A
you'll have
// test[C]() // doesn't compile, could not find implicit value for parameter makeT: MakeT[C]
Regarding generic return type see also
Why can't I return a concrete subtype of A if a generic subtype of A is declared as return parameter?
Type mismatch on abstract type used in pattern matching
Or you can use standard type classes =:=, <:<
def test[T <: A]()(implicit ev: B =:= T): T = {
new B {}
}
(not implicit ev: T =:= B)
or
def test[T <: A]()(implicit ev: B <:< T): T = {
new B {}
}

Shapeless: Iterate over the types in a Coproduct

I want to do something really simple, but I'm struggling to craft the correct search or just understanding some of the solutions I've seen.
Given a method that takes a generic type parameter which is a Coproduct;
def apply[T <: Coproduct] = {
...
}
How can I iterate over the types that form the coproduct? Specifically, for each type that is a case class, I'd like to recursively examine each field and build up a map with all the information.
Currently I'm working around this using a builder pattern, which I'll post here in case it's useful to others;
class ThingMaker[Entities <: Coproduct] private {
def doThings(item: Entities): Set[Fact] = {
...
}
def register[A <: Product with Serializable]: ThingMaker[A :+: Entities] = {
// useful work can be done here on a per type basis
new ThingMaker[A :+: Entities]
}
}
object ThingMaker {
def register[A <: Product with Serializable]: ThingMaker[A :+: CNil] = {
// useful work can be done here on a per type basis
new ThingMaker[A :+: CNil]
}
}
If you just want to inspect values, you can simply pattern match on a coproduct like on any other value...
def apply[T <: Coproduct](co: T): Any = co match {
case Inl(MyCaseClass(a, b, c)) => ???
...
}
...but if you want to be more precise than that, for instance to have a return type that depends on the input, or to inspect the types inside this coproduct to summon implicits, then you can write the exact same pattern matching expression using a type class and several implicit definition:
trait MyFunction[T <: Coproduct] {
type Out
def apply(co: T): Out
}
object MyFunction {
// case Inl(MyCaseClass(a, b, c)) =>
implicit val case1 = new MyFunction[Inl[MyCaseClass]] {
type Out = Nothing
def apply(co: Inl[MyCaseClass]): Out = ???
}
// ...
}
In general, when you want iterate over all types of a coproduct, you will always follow the same tail recursive structure. As a function:
def iterate[T <: Coproduct](co: T): Any = co match {
case Inr(head: Any) => println(v)
case Inl(tail: Coproduct) => iterate(tail)
case CNil => ???
}
Or as a "dependently typed function":
trait Iterate[T <: Coproduct]
object Iterate {
implicit def caseCNil = new Iterate[CNil] {...}
implicit def caseCCons[H, T <: Coproduct](implicit rec: Iterate[T]) =
new Iterate[H :+: T] {...}
}
You can for instance ontain the name of each type in a coproduct using an addition ClassTag implicit:
trait Iterate[T <: Coproduct] { def types: List[String] }
object Iterate {
implicit def caseCNil = new Iterate[CNil] {
def types: List[String] = Nil
}
implicit def caseCCons[H, T <: Coproduct]
(implicit
rec: Iterate[T],
ct: reflect.ClassTag[H]
) =
new Iterate[H :+: T] {
def types: List[String] = ct.runtimeClass.getName :: rec.types
}
}
implicitly[Iterate[Int :+: String :+: CNil]].types // List(int, java.lang.String)
Because of the way Scala lets you influence implicit priority, it's actually possible to translate any recursive function with pattern matching into this "dependently typed function" pattern. This is unlike Haskell where such function can only be written if call cases of the match expression are provably non-overlapping.

Type equality in Scala

Here is a little snippet of code:
class Foo[A] {
def foo[B](param: SomeClass[B]) {
//
}
}
Now, inside foo, how do I:
1) verify if B is the same type as A?
2) verify if B is a subtype of A?
You need implicit type evidences, <:< for subtype check and =:= for same type check. See the answers for this question.
As a side note, generalized type constraints aren't actually necessary:
class Foo[A] {
def foo_subParam[B <: A](param: SomeClass[B]) {...}
def foo_supParam[B >: A](param: SomeClass[B]) {...}
def foo_eqParam[B >: A <: A](param: SomeClass[B]) {...}
def foo_subMyType[Dummy >: MyType <: A] {...}
def foo_supMyType[Dummy >: A <: MyType] {...}
def foo_eqMyType[Dummy1 >: MyType <: A, Dummy2 >: A <: MyType] {...}
}
In fact, I prefer this way, because it both slightly improves type inference and guarantees that no extraneous runtime data is used.
1) verify if B is the same type as A?
class Foo[A] {
def foo(param: SomeClass[A]) = ???
}
// or
class Foo[A] {
def foo[B](param: SomeClass[B])(implicit ev: A =:= B) = ???
}
2) verify if B is a subtype of A?
class Foo[A] {
def foo[B <: A](param: SomeClass[B]) = ???
}
// or
class Foo[A] {
def foo[B](param: SomeClass[B])(implicit ev: B <:< A) = ???
}
In your case, you do not need generalized type constraints (i.e. =:=, <:<). They're required when you need to add a constraint on the type parameter that is defined elsewhere, not on the method.
e.g. To ensure A is a String:
class Foo[A] {
def regularMethod = ???
def stringSpecificMethod(implicit ev: A =:= String) = ???
}
Here you cannot enforce the type constraint without a generalized type constraint.

Constraining an operation by matching a type parameter to an argument's path-dependent type

I would like to exploit Scala's type system to constrain operations in a system where there are versioned references to some values. This is all happening in some transactional context Ctx which has a version type V attached to it. Now there is a Factory to create reference variables. They get created with a creation version attached them (type parameter V1), corresponding to the version of the context in which the factory was called.
Now imagine that some code tries to access that reference in a later version, that is using a different Ctx. What I want to achieve is that it is prohibited to call access on that Ref in any version (Ctx's V type field) that doesn't match the creation version, but that you are allowed to resolve the reference by some substitution mechanism that returns a new view of the Ref which can be accessed in the current version. (it's ok if substitute is called with an invalid context, e.g. one that is older than the Ref's V1 -- in that case a runtime exception could be thrown)
Here is my attempt:
trait Version
trait Ctx {
type V <: Version
}
object Ref {
implicit def access[C <: Ctx, R, T](r: R)(implicit c: C, view: R => Ref[C#V, T]): T =
view(r).access(c)
implicit def substitute[C <: Ctx, T](r: Ref[_ <: Version, T])
(implicit c: C): Ref[C#V, T] = r.substitute(c)
}
trait Ref[V1 <: Version, T] {
def access(implicit c: { type V = V1 }): T // ???
def substitute[C <: Ctx](implicit c: C): Ref[C#V, T]
}
trait Factory {
def makeRef[C <: Ctx, T](init: T)(implicit c: C): Ref[C#V, T]
}
And the problem is to define class method access in a way that the whole thing compiles, i.e. the compound object's access should compile, but at the same time that I cannot call this class method access with any Ctx, only with one whose version matches the reference's version.
Preferably without structural typing or anything that imposes performance issues.
FYI, and to close the question, here is another idea that I like because the client code is fairly clutter free:
trait System[A <: Access[_]] {
def in[T](v: Version)(fun: A => T): T
}
trait Access[Repr] {
def version: Version
def meld[R[_]](v: Version)(fun: Repr => Ref[_, R]): R[this.type]
}
trait Version
trait Ref[A, Repr[_]] {
def sub[B](b: B): Repr[B]
}
object MyRef {
def apply[A <: MyAccess](implicit a: A): MyRef[A] = new Impl[A](a)
private class Impl[A](a: A) extends MyRef[A] {
def sub[B](b: B) = new Impl[B](b)
def schnuppi(implicit ev: A <:< MyAccess) = a.gagaism
}
}
trait MyRef[A] extends Ref[A, MyRef] {
// this is how we get MyAccess specific functionality
// in here without getting trapped in more type parameters
// in all the traits
def schnuppi(implicit ev: A <:< MyAccess): Int
}
trait MyAccess extends Access[MyAccess] {
var head: MyRef[this.type]
var tail: MyRef[this.type]
def gagaism: Int
}
def test(sys: System[MyAccess], v0: Version, v1: Version): Unit = {
val v2 = sys.in(v0) { a => a.tail = a.meld(v1)(_.head); a.version }
val a3 = sys.in(v2) { a => a }
val (v4, a4) = sys.in(v1) { a =>
a.head = a.head
println(a.head.schnuppi) // yes!
(a.version, a)
}
// a3.head = a4.head // forbidden
}
The following seems to work:
trait Version
trait Ctx[+V1 <: Version] {
type V = V1
}
type AnyCtx = Ctx[_ <: Version]
type AnyRf[T] = Ref[_ <: Version, T]
object Ref {
implicit def access[C <: AnyCtx, R, T](r: R)(
implicit c: C, view: R => Ref[C#V, T]): T = view(r).access(c)
implicit def substitute[C <: AnyCtx, T](r: AnyRf[T])(implicit c: C): Ref[C#V, T] =
r.substitute( c )
}
trait Ref[V1 <: Version, T] {
def access(implicit c: Ctx[V1]): T
def substitute[C <: AnyCtx](implicit c: C): Ref[C#V, T]
}
trait Factory {
def makeVar[C <: AnyCtx, T](init: T)(implicit c: C): Ref[C#V, T]
}
// def shouldCompile1(r: AnyRf[String])(implicit c: AnyCtx): String = r
def shouldCompile2(r: AnyRf[String])(implicit c: AnyCtx): String = {
val r1 = Ref.substitute(r)
r1.access(c)
}
// def shouldFail(r: AnyRf[String])(implicit c: AnyCtx): String = r.access(c)
So the follow-up questions are
why I need a redundancy of the type
parameter for Ctx to achieve this. I hate that these type
parameters accumulate like rabbits in my code.
why shouldCompile1 doesn't compile
—can i get the implicits to work as planned?
EDIT:
This is wrong, too. The variance annotation is wrong. Because now the following compiles although it shouldn't:
def versionStep(c: AnyCtx): AnyCtx = c // no importa
def shouldFail3[C <: AnyCtx](f: Factory, c: C): String = {
val r = f.makeVar("Hallo")(c)
val c2 = versionStep(c)
r.access(c2)
}