I'm trying to set a view bound over a high-kinded type and I get an error message that I cannot understand.
$ scala -language:higherKinds
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_43).
Type in expressions to have them evaluated.
Type :help for more information.
scala> trait F[M[_]]
defined trait F
scala> def foo[M[_]](implicit m: M[_] => F[M]) = 42
foo: [M[_]](implicit m: M[_] => F[M])Int
scala> def bar[M[_] <% F[M]] = 42
<console>:8: error: type M takes type parameters
def bar[M[_] <% F[M]] = 42
^
Shouldn't bar compile to the same thing as foo? What am I missing?
Note that there's a subtle distinction between the M[_] in the type parameter list and the type M[_] (i.e., the role the M[_] plays in the function type in the implicit parameter list). The first is a type constructor parameter and the second is an existential type (see sections 4.4 and 3.2.10 of the Scala language specification for more information).
So for example we could replace the type constructor parameter M[_] with M[X] without changing the meaning, but this would be a syntax error in the latter case (which is shorthand instead for something like M[X] forSome { type X }).
The difference may be clearer in the following example (which compiles just fine):
scala> def bar[M[_], M_ <: M[_] <% F[M]] = 42
bar: [M[_], M_ <: M[_]](implicit evidence$1: M_ => F[M])Int
Here the first M[_] is a type constructor parameter, and the second (the upper bound on M_) is an existential type.
The Scala compiler could conceivably make M[_] <% F[M] work as you expect it to here—i.e., it could translate the type constructor parameter into an existential type in the type of the implicit parameter that it creates for the context bound—but that would require an extra little piece of compiler magic, and there's already enough of that to go around.
Related
In Scala, an existential type has the following two forms:
// placeholder syntax
List[_]
// forSome
List[T forSome {type T}]
However, seems that the second form can not appear in the method type parameter position(at least in the way like I write below).
// placeholder syntax is Okay
scala> def foo[List[_]](x: List[_]) = x
foo: [List[_]](x: List[_])List[_]
scala> def foo[List[t forSome {type t}]](x: List[_]) = x
<console>:1: error: ']' expected but 'forSome' found.
def foo[List[T forSome {type T}]](x: List[_]) = x
^
// being as upper bound is also Okay
scala> def foo[A <: List[T forSome { type T }]](x: A) = x
foo: [A <: List[T forSome { type T }]](x: A)A
// type alias is a possible way but that is not what I want
scala> type BB = List[T forSome {type T}]
defined type alias BB
scala> def foo[BB](x: List[_]) = x
foo: [BB](x: List[_])List[Any]
I have tried for a while but been unable to find the right way to get the second compiled successfully.
So is it just some restrictions about method type parameter, or am i missing something here.
The confusion is that the underscore (_) in foo does not denote an existential type.
Let's see what the following actually means:
def foo[List[_]](x: List[_]) = x
List here is a higher kinded type parameter (and by the way does not refer to scala's built-in List type -- aka scala.collection.immutable). This type parameter itself has a single type parameter, denoted by the underscore (_).
Now that it's clear that List[_] is not an existential here, it follows that forSome has no business going there.
However, you can use forSome in the type of x. The following is equivalent to your original definition of foo:
def foo[List[_]](x: List[T] forSome { type T }) = x
Then again, this is probably still not what you'd want, seeing as List is still a type parameter and not scala.collection.immutable. What you'd probably want is:
def foo(x: List[T] forSome { type T }) = x
which is the same as:
def foo(x: List[_]) = x
Hinted by Régis Jean-Gilles's "List here is a higher-kinded type parameter (and by the way does not refer to Scala's built-in List type -- aka scala.collection.immutable)", I had a re-check on the definition of existential type and finally figured out the problem in my case, just write it here as complement for Régis Jean-Gilles's answer.
Existential types are a means of constructing types where portions of the type signature are existential, where existential means that although some real type meets that portion of a type signature, we don’t care about the specific type. Existential types were introduced into Scala as a means to interoperate with Java’s generic types, such as Iterator<?> or Iterator<? extends Component>(Quote from <<Scala In Depth>>).
Real type could be type from the library(like the scala.collection.immutable.List), or the self-defined type like type alias BB in my case. Anyway, Scala compiler has to guarantee that part of the existential type is also known.
The problem in my case is that
// List is type parameter which accepts another type as parameter
def foo[List[_]](x: List[_]) = x
// List may be misleading here, just change it to another name
def foo[TT[_]](x: TT[_]) = x
Scala compiler only knows that TT is higher-kinded type parameter, apparently no real type exists here. So in this case, TT[_] is not a existential type therefore forSome form can not be used in the type parameter position.
And the following cases are valid.
// we define a higher-kined type HKT, so HKT is a real type
// when Scala compiler checks the method parameter part
// HKT can be defined as existential type
def foo[HKT[_]](x: HKT[T forSome { type T }]) = x
def foo[HKT[_]](x: HKT[T] forSome { type T }) = x
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])
Just wondering if the following is a bug or a feature:
Welcome to Scala version 2.10.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class TypeClass[T]
defined class TypeClass
scala> trait A[T] {
| implicit val t = implicitly[TypeClass[T]]
| }
<console>:9: error: could not find implicit value for parameter e: TypeClass[T]
implicit val t = implicitly[TypeClass[T]]
^
As expected, this doesn't compile because there's no constraint on T. But when I add a type annotation it compiles:
scala> trait A[T] {
| implicit val t: TypeClass[T] = implicitly[TypeClass[T]]
| }
defined trait A
Shouldn't the compiler be complaining here? Why should a type annotation make a difference? If we instantiate something with this trait, t is null.
Actually, you are just scr**ing yourself here. :-)
You just declared that the implicit TypeClass[T] is val t. That is, val t = t, which makes it null. Ouch!
T is abstract, so the compiler cannot provide a TypeClass for it. You'd have to get that with the T parameter, but you won't be able to in a trait. In a class, make it T : TypeClass.
I'd say it's neither bug nor feature, just a consequence of some features.
In the first example, there is no implicit value of type TypeClass[T] in scope. You rely on type inference to know the type of t and since implicits are resolved at compile time, the type of t is not defined because the implicit value can't be found.
In the second example there is a suitable implicit value in scope, namely t. If you did not allow that behavior in general you couldn't do recursive definitions like:
val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map{case (x,y) => x+y}
Is it possible to use the context bounds syntax shortcut with higher kinded-types?
trait One { def test[W : ClassManifest]: Unit } // first-order ok
trait Two { def test[W[_]: ClassManifest]: Unit } // not possible??
trait Six { def test[W[_]](implicit m: ClassManifest[W[_]]): Unit } // hmm...
Yes, it is, but your context bound type must have a higher kinded type parameter (which ClassManifest doesn't).
scala> trait HKTypeClass[CC[_]]
defined trait HKTypeClass
scala> implicit def listHKTC = new HKTypeClass[List] {}
listHKTC: java.lang.Object with HKTypeClass[List]
scala> def frob[CC[_] : HKTypeClass] = implicitly[HKTypeClass[CC]]
frob: [CC[_]](implicit evidence$1: HKTypeClass[CC])HKTypeClass[CC]
scala> frob[List]
res0: HKTypeClass[List] = $anon$1#13e02ed
Update
It's possible to use a type alias to allow a higher-kinded type parameter to be bounded by a first-order context bound type. We use the type alias as a type-level function to make a higher-kinded type out of the first-order type. For ClassManifest it could go like this,
scala> type HKClassManifest[CC[_]] = ClassManifest[CC[_]]
defined type alias HKClassManifest
scala> def frob[CC[_] : HKClassManifest] = implicitly[HKClassManifest[CC]]
test: [CC[_]](implicit evidence$1: HKClassManifest[CC])HKClassManifest[CC]
scala> frob[List]
res1: HKClassManifest[List] = scala.collection.immutable.List[Any]
Note that on the right hand side of the type alias CC[_] is a first-order type ... the underscore here is the wildcard. Consequently it can be used as the type argument for ClassManifest.
Update
For completeness I should note that the type alias can be inlined using a type lambda,
scala> def frob[CC[_] : ({ type λ[X[_]] = ClassManifest[X[_]] })#λ] = implicitly[ClassManifest[CC[_]]]
frob: [CC[_]](implicit evidence$1: scala.reflect.ClassManifest[CC[_]])scala.reflect.ClassManifest[CC[_]]
scala> frob[List]
res0: scala.reflect.ClassManifest[List[_]] = scala.collection.immutable.List[Any]
Note that implicitly[ClassManifest[List[_]]] is short for implicitly[ClassManifest[List[T] forSome {type T}]].
That's why it works: ClassManifest expects a proper type argument, and List[T] forSome {type T} is a proper type, but List is a type constructor. (Please see What is a higher kinded type in Scala? for a definition of "proper" etc.)
To make both ClassManifest[List[String]] and ClassManifest[List] work, we'd need to overload ClassManifest somehow with versions that take type parameters of varying kinds, something like:
class ClassManifest[T] // proper type
class ClassManifest[T[_]] // type constructor with one type parameter
class ClassManifest[T[_, _]] // type constructor with two type parameters
// ... ad nauseam
(On an academic note, the "proper" way to do this, would be to allow abstracting over kinds:
class ClassManifest[T : K][K]
implicitly[ClassManifest[String]] // --> compiler infers ClassManifest[String][*]
implicitly[ClassManifest[List]] // --> compiler infers ClassManifest[List][* -> *]
)
Scala 2.8 spec says in section 7.3 (highlighting is mine):
Implicit parameters and methods can also define implicit conversions called views.
A view from type S to type T is defined by an implicit value which has function type
S=>T or (=>S)=>T or by a method convertible to a value of that type.
Views are applied in two situations.
If an expression e is of type T, and T does not conform to the expression’s
expected type pt. In this case an implicit v is searched which is applicable to
e and whose result type conforms to pt. The search proceeds as in the case of
implicit parameters, where the implicit scope is the one of T => pt. If such a
view is found, the expression e is converted to v(e).
[...]
given the above and the following facts:
Long is not a subtype of java.lang.Comparable[Long], i.e. does not conform to type T where T <: java.lang.Comaparable[Long]
Predef contains implicit def longWrapper (x: Long) : RichLong
RichLong is a subtype of java.lang.Comparable[Long], i.e. conforms to type T where T <: java.lang.Comaparable[Long]
I would expect the implicit conversion to be applied where Long is encountered and a subtype of java.lang.Comparable[Long] is expected. However:
scala> def test[T <: java.lang.Comparable[Long]](c: T) = println(c)
test: [T <: java.lang.Comparable[Long]](c: T)Unit
scala> test(12L)
<console>:7: error: inferred type arguments [Long] do not conform to method test's type parameter bounds [T <: java.lang
.Comparable[Long]]
test(12L)
^
The result is as expected if the value is converted explicitly:
scala> test(longWrapper(12L))
12
Why isn't the conversion function applied implicitly?
You need to use a view-bound (<%) to have compiler look for and apply the implicit conversion.
scala> def test[T <% java.lang.Comparable[Long]](c: T) = println(c)
test: [T](c: T)(implicit evidence$1: (T) => java.lang.Comparable[Long])Unit
scala> test(12L)
12
You can read more about view-bound on this page (Ctrl+F for "view bound").