[英]Why is passing Int where an F[_] parameter is expected valid?
Let's say we have a function:假设我们有一个函数:
def bar[F[_], A](x: F[A], y: F[A]) = null
All the following behavior are clear:以下所有行为都是明确的:
bar(List(1, 2, 3), List(1)) // compiles ok
bar(List(1), Some(1)) // doesn't compile
But,但,
bar(1, List(1)) // compiles ok
bar(1, 1) // compiles ok
Why?为什么?
PS example from FSiS Part 1 - Type Constructors, Functors, and Kind Projector FSiS 第 1 部分中的PS 示例- 类型构造函数、函子和种类投影仪
I think you're running into a limitation of the type inference system.我认为您遇到了类型推断系统的限制。 To shed some light on this, let's look at what happens when we redefine this a bit to get a more useful output:为了阐明这一点,让我们看看当我们重新定义它以获得更有用的输出时会发生什么:
class Bar[F[_], A](x: F[A], y: F[A]) {}
res0: Bar[List,Int] = Bar@69f1a286
new Bar(List(1,2,3), List(1))
res1: Bar[Any,Int] = Bar@7b139eab
new Bar(List(1), 1)
res2: Bar[Any,Int] = Bar@456be73c
new Bar(List(1), Some(1))
<console>:12: error: inferred kinds of the type arguments (Product with java.io.Serializable,Int) do not conform to the expected kinds of the type parameters (type F,type A) in class Bar.
Product with java.io.Serializable's type parameters do not match type F's expected parameters:
<refinement of Product with java.io.Serializable> has no type parameters, but type F has one
new Bar(List(1), Some(1))
^
<console>:12: error: type mismatch;
found : List[Int]
required: F[A]
new Bar(List(1), Some(1))
^
<console>:12: error: type mismatch;
found : Some[Int]
required: F[A]
new Bar(List(1), Some(1))
In the first example, we have a Bar[List, Int]
, which makes perfect sense, we passed in two List[Int]
.在第一个示例中,我们有一个Bar[List, Int]
,这很有意义,我们传入了两个List[Int]
。
In the second and third, we have a Bar[Any, Int]
.在第二个和第三个中,我们有一个Bar[Any, Int]
。 Here's where it gets weird.这就是它变得奇怪的地方。 Keep in mind that Any
is the parent of both AnyVal
(the parent of Scala's equivalents of Java's primitives) and AnyRef
(the Scala equivalent of Java's Object) (see Scala Documentation for further explanation).请记住, Any
是AnyVal
(Java 原语等价物的 Scala 等价物的父代)和AnyRef
(Java 对象的 Scala 等价物)的父代(请参阅Scala 文档以获取进一步说明)。
Scala's type inference has decided that this Bar
's constructor should accept Any
for F
, and Int
for A
. Scala 的类型推断已经决定这个Bar
的构造函数应该接受Any
for F
和Int
for A
。 As Any
is indeed a parent of List
and Int
, that's fine.由于Any
确实是List
和Int
的父级,所以没关系。 The List
is indeed parameterized as [Int]
, so that's fine. List
确实被参数化为[Int]
,所以没关系。 What's weird is that Scala is okay with saying that the Int
is also of type Any[Int]
.奇怪的是 Scala 可以说Int
也是Any[Int]
类型。 I don't have a good explanation for that part.我对那部分没有很好的解释。
With the last one, that's where I'm honestly confused, and I have to wonder if this is a bug.对于最后一个,老实说,这就是我感到困惑的地方,我不得不怀疑这是否是一个错误。 For some reason, even though both List
and Some
are children of Any
, and both are parameterized with Int
, it doesn't allow it.出于某种原因,即使List
和Some
都是Any
子代,并且都使用Int
参数化,但它不允许这样做。 I'm afraid I'm not well versed in the intricacies of the compiler's inference methods, but for what it's worth, explicitly specify those parameters works:恐怕我不太精通编译器推理方法的复杂性,但就其价值而言,明确指定这些参数有效:
new Bar[Any,Int](List(1), Some(1))
res14: Bar[Any,Int] = Bar@36238b12
To me, that suggests the type inference system just can't properly infer the types, or it's inferring types that aren't correct.对我来说,这表明类型推断系统无法正确推断类型,或者推断的类型不正确。
This works because the compiler infers some types for you.这是有效的,因为编译器会为您推断一些类型。 Here's what this looks like with the types added into bar
:这是添加到bar
的类型后的样子:
bar[Any, Int](1, List(1)) // compile ok
bar[Any, Nothing](1, 1) // compile ok
This doesn't work for bar(List(1), Some(1))
because the compiler can't infer a type to support both List
and Some
.这对bar(List(1), Some(1))
不起作用,因为编译器无法推断出支持List
和Some
的类型。 You can however downcast this like above, bar[Any, Int](List(1), Some(1))
works.但是,您可以像上面那样向下转换, bar[Any, Int](List(1), Some(1))
有效。
I think the following gives a clue (although there is still some mystery involved):我认为以下提供了一个线索(尽管仍然存在一些谜团):
def baz[F[_], A](x: F[A]): F[A] = x
scala> baz("str")
res5: Comparable[String] = str
scala> baz(1)
res6: Any = 1
scala> class Foo
defined class Foo
scala> baz(new Foo)
<console>:15: error: no type parameters for method baz: (x: F[A])F[A] exist so that it can be applied to arguments (Foo)
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Foo
required: ?F
baz(new Foo)
^
<console>:15: error: type mismatch;
found : Foo
required: F[A]
baz(new Foo)
^
scala> case class Foo2
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
defined class Foo2
scala> baz(Foo2)
res10: scala.runtime.AbstractFunction0[Foo2] = Foo2
So the functions bar
and baz
are finding any container type they can ( Comparable
for String, AbstractFunction0
for a case class, etc) to match the expected F[_]
.因此,函数bar
和baz
正在寻找它们可以找到的任何容器类型(对于 String 来说是Comparable
,对于案例类来说是AbstractFunction0
等)以匹配预期的F[_]
。
Speculation: in the case of Int
, I suspect we are hitting a special "container" type for what are (boxed) primitive types in the underlying bytecode.推测:在Int
的情况下,我怀疑我们正在针对底层字节码中的(装箱)原始类型使用特殊的“容器”类型。 If this special type can only be printed back to Scala as " Any
", but is really some special type we can think of as " Any[_]
", then that could explain the results we see.如果这个特殊类型只能作为“ Any
”打印回 Scala,但实际上是某种我们可以认为是“ Any[_]
”的特殊类型,那么这可以解释我们看到的结果。 As corroboration that this is to do with the special handling of primitives, note that it fails for non-primitive simple types, like the (non-case) class Foo
above.为了证实这与原始类型的特殊处理有关,请注意它对于非原始简单类型失败,例如上面的(非大小写)类Foo
。
It seems there's something wired going on with the Any
type in combination with the kind system. Any
类型与 kind 系统相结合似乎有一些关联。
Any
doesn't take a type parameter: val i:Any[Int] = 1
gives an error, so it should be of simple kind. Any
不接受类型参数: val i:Any[Int] = 1
给出错误,所以它应该是简单的类型。
Any
can be used in a position where a higher kinded type is expected, as you showed in your example bar[Any, Nothing](1,1)
Any
可用于需要更高类型类型的位置,如示例bar[Any, Nothing](1,1)
If we use Any
in a higher kinded position this type parameter magically turns into a simple kind and the type parameter of this former higher kinded type is completely ignored.如果我们在更高级的类型位置使用Any
,这个类型参数会神奇地变成一个简单的类型,并且这个之前的高级类型的类型参数被完全忽略。
When the first type parameter of bar
is Any
we can but any type as the second parameter and it will always compile:当bar
的第一个类型参数是Any
我们可以将任何类型作为第二个参数,并且它将始终编译:
bar[Any,String](List(1),List(2))
bar[Any, Boolean](1,2)
bar[Any, Int](List(), true)
case class A()
bar[Any, A](List, A)
There seems to be a problem with the type inference that leads some examples to fail without type annotations.类型推断似乎存在问题,导致一些示例在没有类型注释的情况下失败。
I have found out about this behavior by trial and error, I don't know if it's bug or a feature ;-)我通过反复试验发现了这种行为,我不知道这是错误还是功能;-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.