Two related existential type parameters - scala

Let's take this example code:
trait DataProcessor[D] {
def computeData(): D
}
case class DataItem[D, P <: DataProcessor[D]](processor: P, data: D)
def computeDataFromItems(items: Set[DataItem[_, _]]) = items collectFirst {
case DataItem(s: DataProcessor[_], d) =>
s.computeData()
}
When compiled with Scala 2.11, it yield this error:
Error:(8, 77) type arguments [_$1,_$2] do not conform to class DataItem's type
parameter bounds [D,P <: TwoExistentials.DataProcessor[D]]
def computeDataFromItems(items: Set[DataItem[_, _]]) = items collectFirst {
It seems that the collectFirst method needs some more type information, that is not contained in the pair of existential types of the DataItem class.
Is there a chance to give more specific types to the method's arguments, something like:
def computeDataFromItems(items: Set[DataItem[D, P] forSome { type D, type P <: DataProcessor[D] }])
which unfortunately doesn't compile?
Otherwise, is there a way to allow for a class with two related type parameters to be used in collections, in a type-safe manner?
By the way, I have already considered using shapeless, instead of existential types. But I am looking for an implementation with classical Scala collections.

This should compile (replaced , with ;):
def computeDataFromItems(items: Set[DataItem[D, P] forSome { type D; type P <: DataProcessor[D] }])

Related

Is it possible for Scala to infer types for Generic types passed into a dependent class?

Given the following:
trait A[X] {
def foo(): X
}
class B[T <: A[_]] {
def getFoo(a:T) = a.foo()
}
class C[T <: A[Z], Z] {
def getFoo(a:T):Z = a.foo()
}
Is it possible to make B work like C? Specifically getting the result type of a.foo().
scala> var b:B[A[Int]] = new B[A[Int]]()
scala> b.getFoo(AA(1))
res0: Any = 1
scala> var c:C[A[Int],Int] = new C[A[Int],Int]()
c: C[A[Int],Int] = C#4cc36c19
scala> c.getFoo(AA(1))
res1: Int = 1
b returns an Any, but c correctly returns an Int. This is obviously a contrived example, but it would greatly simplify by code if I could extract a subtype from a Generic type. Basically, knowing "Z" (as used in C) without having to pass it in explicitly - inferring from the type of A.
Obviously, C works as needed, but the issue is my framework is more akin to:
class D[T <: A[Z1], U <: B[Z2], Z1, Z2] extends E[T,U,Z1,Z2]
which then requires users of the framework to implement with 4 type parameters, when ideally it would only be 2
class D[T <: A[_], U <: B[_]] extends E[T,U]
Not a blocker, just an attempt at simplifying the exposed API.
You can do the following which is often used in certain typeclass based libraries:
trait Foo[H[_] <: Langh[_]]{
def thing[A](ha: H[A]): A = ha.ha()
}
This pushes the resolution of the type parameter to the invocation of the method thing. It uses higher-kinded types.
If fact, if you look at libs like ScalaZ, you'll see exactly this pattern:
trait Functor[F[_]]{
def map[A, B](fa: F[A])(f: A => B): F[B]
}
Reply to Comments
There is no way to have a type of U <: T[_] and then be able to extract out the type parameter of an actual T[A] because the very definition of it loses that information. If the above does not work for you, then I would suggest type classes:
trait Foo[U]{
def doStuff(u: U)(implicit ev: MyTypeClass[U]): ev.A = //...
}
wherein you only define your MyTypeClass implicits like the following:
trait Whatever[FA]{ /*...*/ }
object Whatever{
implicit def WhateverMTC[F[_] <: Bound[_], A0] = new MyTypeClass[F[A0]]{
type A = A0
//...
}
}
Then you can place your type bound on the implicit, your implicit carries with it the constraint that your type must be higher-kinded and you can get a method that returns the inner "hidden" type at the call site declaration.
That said, this is a lot of machinery when the first suggestion is much more elegant and a cleaner approach to the problem IMHO.

F-bounded existential quantification

I came across the existential quantification for F-bounded types while trying to understand scala's type system.
Let A be a type
trait A[F <: A[F]] { self: F => }
where F is the F-bounded self-type of A.
And B some subtype of A
case class B() extends A[B]
If I try to declare a List of A with existential quantification
val a: List[T] forSome { type T <: A[T] }
I get an error when assigning a a List of B. For some reason scala infers the type List[A[Nothing]].
val a: List[T] forSome { type T <: A[T] } = List(B()) // type mismatch
When applying the simplification rule 4 (as described in the scala-spec) the covariant occurrence of T may be replaced by the upper bound (here: A[T])
val b: List[A[T]] forSome { type T <: A[T] } = List(B())
Both examples should be equivalent (if I have not misunderstood something), but the simplified one works just fine. Furthermore the following is also correct and should be equivalent:
val c: List[T forSome { type T <: A[T] }] = List(B())
But for some reason the type of c and the type of b are not equal.
So my question is: Is this a bug of the scala compiler or did I misunderstand something crucial?
Edit: Is my assumption correct, that the types of c and b are not equal, because the existential quantification in c does not see the covariant occurrence of T?

scala: overriding a value of generic, existential type with a concretised type

I have a generic trait MappingPath, invariant regarding it's type parameters:
trait MappingPath[X<:AnyMapping, Y<:AnyMapping]
and an interface of a factory for it:
trait Pathfinder[X, Y] {
def apply(fun :X=>Y) :MappingPath[_<:AnyMapping,_<:AnyMapping]
def get(fun :X=>Y) :Option[MappingPath[_<:AnyMapping, _<:AnyMapping]]
}
I start a skeleton implementation which works for a single mapping:
class MappingPathfinder[M<:AnyMapping, X, Y] extends Pathfinder[X, Y] {
override def apply(fun :X=>Y) :MappingPath[M, _<:AnyMapping] = ???
override def get(fun :X=>Y) :Option[MappingPath[M, _<:AnyMapping]] = ???
}
which produces a compile error complaining that MappingPathfinder.apply overrides nothing and doesn't implement Pathfinder.apply. What's interesting, replacing M with _<:AnyMapping in apply's return type makes it compile, and no complaints are made regarding similar get method.
What's going on? I use scala 2.11.5.
EDIT:
I was able to circumvene my problem by adding explicit existantial annotations:
//Pathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A<:AnyMapping; type B<:AnyMapping }
//MappingPathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A>:M<:M; type B<:AnyMapping }
It seems to work, i.e
I can do:
(p :MappingPath[_<:AnyMapping, M]) ++ mappingPathfinder(f),
where ++ requires a path starting with the exact same type as this ends. It looks a bit silly and certainly confusing though.
Not an answer, but your use case can be simplified to:
trait Higher[U]
trait Super {
def foo: Higher[_]
}
trait Sub[M] {
override def foo: Higher[M] // error: method foo overrides nothing
}
Instead of existential types, I would use a type member:
trait Super {
type U
def foo: Higher[U]
}
trait Sub[M] {
type U = M
}
I think the difference is that in the case of the existential type, you only specify that the type parameter returned has some upper bound, but not necessarily that it is always the same type; whereas in my second example, type U means this will eventually be one specific type, and you can only refine a specific type. You can make upper bounds more precise:
trait Upper
trait A {
type U <: Upper
}
trait Specific extends Upper
trait B extends A {
type U <: Specific // type is "overridden"
}
If it's possible, I would avoid existential types, and your case seems a perfect fit for such avoidance. Most of the time, existential types are only needed for Java interop.

Scala: type inference of generic and it's type argument

Lets assume I have instance of arbitrary one-argument generic class (I'll use List in demonstration but this can me any other generic).
I'd like to write generic function that can take instances (c) and be able to understand what generic class (A) and what type argument (B) produced the class (C) of that instance.
I've come up with something like this (body of the function is not really relevant but demonstrates that C conforms to A[B]):
def foo[C <: A[B], A[_], B](c: C) {
val x: A[B] = c
}
... and it compiles if you invoke it like this:
foo[List[Int], List, Int](List.empty[Int])
... but compilation fails with error if I omit explicit type arguments and rely on inference:
foo(List.empty[Int])
The error I get is:
Error:Error:line (125)inferred kinds of the type arguments (List[Int],List[Int],Nothing) do not conform to the expected kinds of the type parameters (type C,type A,type B).
List[Int]'s type parameters do not match type A's expected parameters:
class List has one type parameter, but type A has one
foo(List.empty[Int])
^
Error:Error:line (125)type mismatch;
found : List[Int]
required: C
foo(List.empty[Int])
^
As you can see Scala's type inference cannot infer the types correctly in this case (seems like it's guess is List[Int] instead of List for 2nd argument and Nothing instead of Int for 3rd).
I assume that type bounds for foo I've come up with are not precise/correct enough, so my question is how could I implement it, so Scala could infer arguments?
Note: if it helps, the assumption that all potential generics (As) inherit/conform some common ancestor can be made. For example, that A can be any collection inherited from Seq.
Note: the example described in this question is synthetic and is a distilled part of the bigger problem I am trying to solve.
This is a known limitation of current Scala's type inference for type constructors. Defining the type of formal parameter c as C only collects type constraints for C (and indirectly to A) but not B. In other words List[Int] <: C => { List[Int] <: C <: Any, C <: A[_] <: Any }.
There is a pretty simple translation that allows to guide type inference for such cases. In your case it is:
def foo[C[_] <: A[_], A[_], B](c: A[B]) { val x: A[B] = c }
Same semantics, just slightly different type signature.
In addition to hubertp answer, you can fix you function by removing obsolete (in you example) type variable C, e.g:
def foo[A[_], B](c: A[B]) {
val x: A[B] = c
}
In this case scalac would infer A[_] as List and B as Int.
Update (according to the comment).
If you need an evidence that C is subtype of A[B], then use implicit:
def foo[A[_], B, C](c: C)(implicit ev: C <:< A[B]) = {
val x: A[B] = c
}
Then it won't compile this:
scala> foo[List, String, List[Int]](List.empty[Int])
<console>:9: error: Cannot prove that List[Int] <:< List[String].
foo[List, String, List[Int]](List.empty[Int])

Partially applying type parameters

I'm desperately trying to solve the following:
trait Access[Res[_]] { def access[C]: Res[C] }
trait CList[C1, A] extends Access[CList[_, A]] // ?!
def test[C1, C2, A](c: CList[C1, A]): CList[C2, A] = c.access[C2]
scalac just says: "error: illegal cyclic reference involving trait CList". how can I make this compile?
You might be interested in type lambdas. The partial application you used in your answer is actually implemented in scalaz.
As the code tends to get less readable though, they started using type lambdas instead. The type in question could be written as
({type λ[α] = CList[α,A]})#λ
This works by creating a type projection on a parameterized type λ inside a structural type thus capturing the outer type parameter (in this case A).
The other problem concerning variance described in your answer could be solved by making the Res parameter in Access covariant.
After these changes your code should look like this:
trait Access[+Res[_]] { def access[C] : Res[C]}
trait CList[C, +A] extends Access[({type λ[α] = CList[α,A]})#λ]
googling for "partial type application" i found this solution posted by James Iry on the scala debate list ( http://scala-programming-language.1934581.n4.nabble.com/Partial-type-inference-td2007311.html ; adapted so the arg order is changed):
type Partial2[T[_,_], B] = {
type Apply[A] = T[A,B]
}
trait CList[C1, A] extends Access[Partial2[CList, A]#Apply]
cheese louise, is this really the only way to do that in scala in 2011 ?!!
EDIT:
This fails with covariance in A :,-(
trait Access[Res[_]] { def access[C]: Res[C] }
type Partial2[T[_,_], B] = {
type Apply[A] = T[A,B]
}
trait CList[C1, +A] extends Access[Partial2[CList, A]#Apply]
"covariant type A occurs in invariant position"
Just to update things
add this compiler plugin to your sbt for kind projection and you'll get a nice syntax using ?. This removes the type projection boilerplate which looks messy!
So you can write stuff like Either[String, ?]
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
it's implemented with the same old type projection underneath
You can also find it here: https://underscore.io/blog/posts/2016/12/05/type-lambdas.html
I know this is a really old question, but anyway:
trait AnyAccess {
type Res[X]
def access[Z]: Res[Z]
}
trait AnyCList extends AnyAccess { me =>
type C
type A
// this could be a subtype bound instead, if needed
type Res[X] = AnyCList { type C = X; type A = me.A }
}
case object AnyCList {
type of[C0, +A0] = AnyCList { type C = C0; type A <: A0 }
}
case object buh {
def test[C1, C2, A](c: AnyCList.of[C1, A]): AnyCList.of[C2, A] = c.access[C2]
}
Here's a method that worked for me to "partially apply type parameters":
I had a function like
def foo[A, B, C, D, E](...)
Such that I needed to hint only one type parameter for the compiler to infer the rest. This worked for me:
object InferType {
type InferType[A] = Option[A]
def apply[A]: Option[A] = None
}
Update foo to take an additional parameter of type InferType:
// t parameter is unused in implementation but
// is used by compiler to infer other type parameters
def foo[A, B, C, D, E](..., t: InferType[D])
Usage:
foo(..., InferType[ConcreteD])