implicitly convert higher order type - scala

I'm a scala newbie...so assume ignorance.
so if I look at the definition of <:<
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
and this is used to define evidence that a type A is a subtype of B.
A <: B
...but what if I want to have evidence that;
forall T. A[T] <: B[T]
?
ok....so I try to follow the same recipe
abstract class Foo[-A[_],+B[_]] { def apply[C](x : A[C]) : B[C] }
implicit def conforms[A[_]] : Foo[A,A] = new Foo[A,A] { def apply[C](x : A[C]) : A[C] = x }
I can use this constraint an manually apply the conversion, but I can't get the compiler to implicitly "apply" it. (because it doesn't extend A=>B?)
so for example if I define;
abstract class FooInt[-A[_],+B[_]] extends (A[Int] => B[Int])
implicit def conformsInt[A[Int]] : FooInt[A,A] = new FooInt[A,A] { def apply(x : A[Int]) : A[Int] = x }
then the compiler will automatically apply the conversion to values of type A[Int]
I just want to generalise this to A[T]
thoughts?

sealed abstract class <:< - this tells you that you cannot construct "new evidence". You have to rely on the compiler confirming that two existing types do meet the existing evidence. This should work for all types already, if not, you try to proof something that is wrong.
You state you want proof that A[T] <: B[T] forAll { type T }. This will depend on the variance of A's and B's type parameter. If you want to ignore that parameter, you can only ask for evidence A[_] <:< B[_]. E.g.
trait Animal; trait Cat extends Animal
trait Foo[A]
trait Bar[A] extends Foo[A]
implicitly[Bar[Cat] <:< Foo[Cat]] // ok, A is fixed
implicitly[Bar[Cat] <:< Foo[Animal]] // not possible
implicitly[Bar[Animal] <:< Foo[Cat]] // not possible
implicitly[Bar[_] <:< Foo[_]] // ok, we forget about A
If you had variances, you could preserve A:
trait Breeds[+A] // covariant, can "produce" A
trait Feeds [-A] // contravariant, can "consume" A
class Baz[A] extends Breeds[A] with Feeds[A]
implicitly[Baz[Cat] <:< Feeds[Animal]] // nope
implicitly[Baz[Animal] <:< Feeds[Cat]] // ok
implicitly[Baz[Cat] <:< Breeds[Animal]] // ok
implicitly[Baz[Animal] <:< Breeds[Cat]] // nope

Related

Type bounds constraints restrictions in Higher Kinds when extending a trait

Let's set up issue conditions
trait Bound
trait Bound2 extends Bound
trait T1[B <: Bound]
trait T2[B <: Bound2] extends T1[B]
trait WrapperT1[Tz[B2 <: Bound] <: T1[B2]]
This code compile without problem, issue comes when trying to extend WrapperT1
trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
// Compilator error
kinds of the type arguments (T2) do not conform to the expected kinds of the type parameters (type Tz) in trait WrapperT1.
[error] ex.T2's type parameters do not match type Tz's expected parameters:
[error] type B's bounds <: Bound2 are stricter than type B2's declared bounds <: ex.Bound
[error] trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
Yes B2 <: Bound2 is stricter than B2 <: Bound but i'm not understanding why the compilator complains for this reason and i would be grateful to know more about it.
Potential solution but does it has some drawbacks ?
trait Bound
trait Bound2 extends Bound
trait T1[B] {
implicit val ev: B <:< Bound
}
trait T2[B] extends T1[B] {
// this is possible thank's to covariance of class `<:<[-From, +To]` if i'm not wrong
implicit val ev: B <:< Bound2
}
trait WrapperT1[Tz[B2] <: T1[B2]]
// Compiles
trait WrapperT2[Tz[B2] <: T2[B2]] extends WrapperT1[Tz]
This looks nice and we keep the compilation checks about B2 generic type but is there any inconveniant using it ?
To understand why the compiler complains, let's look at this piece of code (which is the same as your code, but with different names)
trait Show[A <: AnyRef] {
def show(a: A): Unit
}
trait ShowString[S <: CharSequence] extends Show[S] {
def show(s: S): Unit = println(s)
}
trait Wrapper1[S[A <: AnyRef] <: Show[A]] {
def show[A <: AnyRef](a: A)(implicit show: S[A]): Unit = show.show(a)
}
trait Wrapper2[S[C <: CharSequence] <: ShowString[C]] extends Wrapper1[S]
Here, too, the compiler emits the error type C's bounds <: CharSequence are stricter than type A's declared bounds <: AnyRef, but let's pretend you somehow get it to compile here. That would mean if someone wanted to use your wrapper class to print, say, a list, they wouldn't be able to do that, meaning that your wrapper class would be basically useless.
val w2: Wrapper[ShowString] = ???
w2.show(List(1, 2))
//Error: could not find implicit value for parameter show: ShowString[List[Int]]
In this case, it's just that the implicit isn't found. However, if you have a method in wrapper that accepts a S[_] (or Tz[_], from your example) and you try to shoehorn an object of the wrong type into your show method, you could get a runtime exception.
It fails for the same reason you can't do this
trait T1[A] {
def process(a: A): Unit
}
trait T2 extends T1[Int] {
def process(i: Int): Unit = ???
}
val t2: T2 = ???
t2.process("not an int")
T2 is just not equipped to handle anything that is not an Int, and the same applies here.

Scala Upper type bounds implicitly?

I have a first trait like this :
trait FirstTrait[U] {
val myVal: U
}
And another one as follows :
trait SecondTrait[T <: firstTrait[U],U]
For the implementation I am doing :
case class FirstImpl(myVal: MyType) extends FirstTrait[MyType]
object SecondImpl extends SecondTrait[FirstImpl,MyType]
Is there a better way to do the same thing, I would like to simplify my implementation of the second trait like this if possible :
object SecondImpl extends SecondTrait[FirstImpl]
EDIT
I am using after both type in a function :
def func[T <: FirstTrait[U],U](myVal: T): U
When I use existential type, I have to explicit types or I get an "inferred type arguments [FirstImpl,Nothing] do not conform to method func" error.
So this is how I have to implement the function :
val myVal : MyType = MyType()
func[FirstImpl,MyType](FirstImpl(myVal))
Can anything simplify?
You can try existential type
trait FirstTrait[U] {
type _U = U
val myVal: U
}
trait SecondTrait[T <: FirstTrait[_]]
case class FirstImpl(myVal: MyType) extends FirstTrait[MyType]
object SecondImpl extends SecondTrait[FirstImpl]
def func[T <: FirstTrait[_]](myVal: T): myVal._U = ???
func(FirstImpl(myVal)): MyType
or
trait FirstTrait {
type U
val myVal: U
}
trait SecondTrait[T <: FirstTrait]
case class FirstImpl(myVal: MyType) extends FirstTrait { type U = MyType }
object SecondImpl extends SecondTrait[FirstImpl]
def func[T <: FirstTrait](myVal: T): myVal.U = ???
func(FirstImpl(myVal)): MyType
or
def func[T, U](myVal: T)(implicit ev: T <:< FirstTrait[U]): U = ???
def func[T <: FirstTrait[U],U](myVal: T): U
The problem is that the type of myVal doesn't mention U, so the compiler is failing to infer it simultaneously with T. If it inferred T first, it could get U from it, but it doesn't currently work this way.
However, T is actually useless here and it can be rewritten as
def func[U](myVal: FirstTrait[U]): U
You can already pass any subtype of FirstTrait[U] here and lose the source of the type inference problem.
If this is a simplified signature, a trick which can work is mentioning U in the parameter type even if it should be redundant:
def func[T <: FirstTrait[U], U](myVal: T with FirstTrait[U]): U

Inference of underscore types

[ I was unable to explain the problem with less verbosity. The core of the issue is that the compiler infers an underscore (_) type. In particular, [_ >: SomeType <: SomeOtherType]. I am clueless about when, how and why that is possible ]
As a scala exercise, I am trying to encode a vector of elements with a given size.
As a necessary step, I started by copying an existing encoding of natural numbers:
sealed trait Natural extends Product with Serializable {
def +(that: Natural): Natural
}
case object Zero extends Natural {
override def +(that: Natural): Natural = that
}
final case class Suc[N <: Natural](n: N) extends Natural {
override def +(that: Natural): Natural = Suc(n + that)
}
I believe the following diagram is a faithful portrayal of the type relation:
I then attempted to model a vector parameterized by a type on the elements and another type on size. To explain the problem though, I assumed a vector of ints and parameterized only the size of the vector :
import shapeless.=:!=
sealed trait Vector[+Size <: Natural] extends Product with Serializable {
def head: Int
def tail: Vector[Natural]
def plus[OtherSize >: Size <: Natural]
(that: Vector[OtherSize])
(implicit ev: OtherSize =:!= Natural): Vector[OtherSize]
}
case object VectorNil extends Vector[Zero.type] {
override def head: Nothing = throw new Exception("Boom!")
override def tail: Vector[Zero.type] = throw new Exception("Boom")
override def plus[OtherSize >: Zero.type <: Natural]
(that: Vector[OtherSize])
(implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = this
}
final case class VectorCons[N <: Natural](
head: Int,
tail: Vector[N]
) extends Vector[Suc[N]] {
override def plus[OtherSize >: Suc[N] <: Natural]
(that: Vector[OtherSize])
(implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = that
}
Notice that VectorCons[N] is actually a Vector of size Suc[N]. (extends Vector[Suc[N]]).
Method plus should add the elements of two vectors of the same size. I wanted to raise to the type level the verification that you can only sum vectors of the same size.
Notice that the conjunction of the type bounds OtherSize >: Size <: Natural with the implicit evidence should achieve that (see similar example at the bottom), but:
val foo = VectorCons(1, VectorCons(2, VectorNil))
//type -> VectorCons[Suc[Zero.type]]
// note that foo is (can be viewed) as Vector[Suc[Suc[Zero.type]], i.e
// a vector of 2 elements
val bar = VectorCons(3, VectorNil)
//type -> VectorCons[Zero.type]
val baz = foo.plus(bar)
//type -> Vector[Suc[_ >: Suc[Zero.type] with Zero.type <: Natural]] !! How is this possible ?? !!
to my frustration, baz compiles just fine!! The shapeless type constrain doesn't work; well, because OtherSize really is different from Natural; particularly, it is Suc[_ >: Suc[Zero.type] with Zero.type <: Natural].
So, I am very much confused with the type of baz! This is what allows the constraint to be bypassed.
What did the compiler infer for the type of baz/bar?
Is that an existential type ?
Is the compiler allowed to infer such things?
Is that not undesirable behavior ?
At this point, I am not concerned whether or not this is the correct encoding for a vector. Just wanted to understand how can the compiler infer that type for baz ?
p.s
1 - I am aware the return that on the implementation of method plus on VectorCons does not achieve what the plus semantics implies, but that is not important for the question.
###### Extra #######
I suspect this weird (at least for me) behavior has something to to with the natural numbers. The following code works fine!! :
[Disregard the absurd semantics of the code]
sealed trait Animal extends Product with Serializable
case class Dog() extends Animal
case class Cow() extends Animal
case object NoBox extends Animal //Not important
and,
trait Vector[+A <: Animal] {
def head: A
def plus[That >: A <: Animal]
(that: Vector[That])
(implicit ev: =:!=[That, Animal]): Vector[That]
}
case object Nil extends Vector[NoBox.type] {
def head: Nothing = throw new NoSuchElementException("Boom!")
override def plus[That >: NoBox.type <: Animal]
(that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = this
}
case class Cons[A <: Animal](head: A) extends Vector[A] {
override def plus[That >: A <: Animal]
(that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = that
}
whereby:
val foo = Cons(Dog())
val bar = Cons(Cow())
// Compiles
val baz = foo.plus(foo)
val baz2 = bar.plus(bar)
// Does not compile (what I would expect)
val baz3 = bar.plus(foo)
val baz4 = foo.plus(bar)
Thank you for your input,

Upper type bound allowing subtypes but not the parent type

Is it possible to have a generic method with an type bound that amounts to "every possible concrete subclass of this trait, but not the trait itself?"
As an example, suppose I have the following inheritance hierarchy:
sealed trait Fruit
case class Apple() extends Fruit
case class Orange() extends Fruit
...
case class Watermelon() extends Fruit
I want to define a method def eatFruit[T <: ???](fruit: Seq[T]) that will allow T to be of type Apple, Orange, Watermelon, etc. but not of type Fruit. The type bound [T <: Fruit] obviously doesn't do the job.
The original impetus for this is that we have a FruitRepository class that allows batched/bulk inserts of different fruits. The batching is done externally to the class, so at the moment it has a lot of methods along the lines of saveApples(apples: Seq[Apple]), saveOranges(oranges: Seq[Orange]), etc. that contain a lot of duplicate logic involving the creation of a batch update statement. I'd like to manage this in a more generic way, but any method saveFruit(fruit: Seq[Fruit]) would allow for e.g. a list containing both apples and oranges, which the repository can't handle.
...I'll also admit that I'm now generally curious as to whether this sort of type bound is possible, even if we end up solving the repository problem in a different way.
We can combine the upper bound directive with a custom implicit enforcement of type inequality. Taken from here (or generally see: Enforce type difference):
#annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.")
trait =!=[A, B]
object =!= {
class Impl[A, B]
object Impl {
implicit def neq[A, B] : A Impl B = null
implicit def neqAmbig1[A] : A Impl A = null
implicit def neqAmbig2[A] : A Impl A = null
}
implicit def foo[A, B](implicit e: A Impl B): A =!= B = null
}
And then we do:
def eatFruit[T <: Fruit](implicit ev: T =!= Fruit) = ???
And when we call it:
def main(args: Array[String]): Unit = {
eatFruit[Fruit]
}
We get:
Error:(29, 13) Cannot prove that yuval.tests.FooBar.Fruit =!= yuval.tests.FooBar.Fruit.
eatFruit[Fruit]
But this compiles:
eatFruit[Orange]
All the magic here is due to creating ambiguity of implicits in scope for the pair [A, A] such that the compiler will complain.
We can also take this one step further, and implement our own logical type, for example, let's call it =<:=!=. We can change the previous implementation a bit:
#annotation.implicitNotFound(msg = "Cannot prove that ${A} =<:=!= ${B}.")
trait =<:=!=[A,B]
object =<:=!= {
class Impl[A, B]
object Impl {
implicit def subtypeneq[B, A <: B] : A Impl B = null
implicit def subneqAmbig1[A] : A Impl A = null
implicit def subneqAmbig2[A] : A Impl A = null
}
implicit def foo[A, B](implicit e: A Impl B): A =<:=!= B = null
}
And now:
case class Blue()
def main(args: Array[String]): Unit = {
eatFruit[Fruit] // Doesn't compile
eatFruit[Blue] // Doesn't compile
eatFruit[Orange] // Compiles
}

How to pattern-match a generic type argument?

I'm currently unable to wrap my head around Scala's TypeTag reflection API. There are very little information to find on the web and all trial and error attempts are leading nowhere.
def doStuff[T: TypeTag]( param: String ): SomeStuff[E] =
{
val t = typeOf[T]
if( <t extends one specific Trait from my application and is an object> )
{
<retrieve that companion object and return one of its values>
}
else
{
t match
{
case x if x =:= typeOf[String] => doOtherStuff[String]( param )
case x if x =:= typeOf[Int] => doOtherStuff[Int]( param )
...
}
}
}
The pattern matching with Scala's predefined Types is working. However I didn't manage to check if the supplied generic argument inherits my specific Trait and later on retrieve the companion object of the actual class behind T. Trying with a straight forward typeOf[MyTrait[_, T]] is being rejected by the compiler telling me that no TypeTag is available for MyTag. How do I create it?
In addition the Trait's nasty generic signature MyTrait[M <: MyTrait[M, E], E <: Entity[M, E]] is exacerbating the whole thing.
Besides some helpful ideas to solve this problem I highly appreciate any further reading links (I've read all on SO though).
Use the following to test if it is an object (from this question):
typeOf[Test] <:< typeOf[Singleton]
You can use existential types to get a TypeTag of your trait:
typeOf[MyTrait[M, T] forSome { type M <: MyTrait[M, T] }]
This works if you have a TypeTag[T] in scope and is bound as following:
T <: Entity[_,T]
Minimal example:
trait Entity[M, E]
trait MyTrait[M <: MyTrait[M, E], E <: Entity[M, E]]
class MyEnt extends Entity[Test, MyEnt]
class Test extends MyTrait[Test, MyEnt]
def getType[T <: Entity[_, T] : TypeTag] =
typeOf[MyTrait[M,T] forSome { type M <: MyTrait[M,T] }]
typeOf[Test] <:< getType[MyEnt]
//| res0: Boolean = true
However, this will not work in your case, since T is not properly bounded. Hence you'll have to test against this (with some help from here):
val mts = typeOf[MyTrait[_,_]].typeSymbol
typeOf[Test].baseType(mts) match {
case TypeRef(_, _, List(_, t)) if t <:< typeOf[MyEnt] => true
case _ => false
}