简体   繁体   English

为什么在 F[_] 参数预期有效的地方传递 Int?

[英]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).请记住, AnyAnyVal (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 FInt for A As Any is indeed a parent of List and Int , that's fine.由于Any确实是ListInt的父级,所以没关系。 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.出于某种原因,即使ListSome都是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))不起作用,因为编译器无法推断出支持ListSome的类型。 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[_] .因此,函数barbaz正在寻找它们可以找到的任何容器类型(对于 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.

相关问题 为什么List [Int,Int]不是有效的Scala类型? - Why is List[Int, Int] not a valid Scala type? 使用Int =&gt; F [Boolean]过滤F [List [Int]],其中F是通用的 - Filter a F[List[Int]] using an Int => F[Boolean] where F is generic 将非元组传递给(Int,Int)=&gt;()进行编译,为什么呢? - passing non tuple to (Int,Int)=>() compiles, why? 为什么`def hello [T](f:=&gt; T)= f; hello(()=&gt; 12)是可编译的,但`def hello(f:=&gt; Int)= f; 你好(()=&gt; 12)不是吗? - Why `def hello[T](f: => T) = f; hello(()=>12)` is compilable but `def hello(f: => Int) = f; hello(()=>12)` is not? 当 Int 扩展 AnyVal 时,为什么将 Int =&gt; Int 传递给采用 AnyVal =&gt; Int 的函数会导致类型不匹配? - Why passing Int => Int to a function taking AnyVal => Int results in type mismatch when Int extends AnyVal? 为什么cats Bifunctor[F[_, _]].bimap function中有两个参数组? - Why are there two parameter groups in cats Bifunctor[F[_, _]].bimap function? 为什么VectorMap [Option [Int]]上的flatMap的mapper函数结果不是Vector [Option [Int]]有效? - Why is flatMap on a Vector[Option[Int]] whose mapper function result is not a Vector[Option[Int]] valid? 为什么按名称调用参数期望使用Int类型的参数,而不是()=&gt; Int - Why call-by-name parameter expect parameter of type Int instead of () => Int 为什么方法参数 F 可以与类型构造函数 F 同名? - Why can method parameter F have the same name as type constructor F? 理解`f:Int =&gt; _` - Understanding `f: Int => _`
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM