Scala [F<;:List[A],A]和[F[3;]<;:List[A],A]之间的推理差异
在下面两个类型参数子句中,考虑类型参数Scala [F<;:List[A],A]和[F[3;]<;:List[A],A]之间的推理差异,scala,type-inference,scala-3,type-constructor,Scala,Type Inference,Scala 3,Type Constructor,在下面两个类型参数子句中,考虑类型参数A对类型构造函数的推断的差异 $ scala3-repl scala> def f[F <: List[A], A](as: F) = as def f[F <: List[A], A](as: F): F scala> f(List(42)) val res0: List[Int] = List(42) scala> def f[F[_] <: List[A], A](as: F[A]) = as def f[F[_
A
对类型构造函数的推断的差异
$ scala3-repl
scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F
scala> f(List(42))
val res0: List[Int] = List(42)
scala> def f[F[_] <: List[A], A](as: F[A]) = as
def f[F[_$1] <: List[A], A](as: F[A]): F[A]
scala> f(List(42))
val res1: List[Any] = List(42)
$scala3 repl
scala>def[f def f[f[\u]根据我对您在第二种情况下的定义的解释,f[\u]
是一个List
类型构造函数,但是List[a]
必须是任何Listf[\u]
可以构造的上限,因此a
必须是any
可能你想要的是:
def[f[\p>不是一个完整的答案,只是一些值得思考的东西:我试图构建一个反例,但在假设a
将被推断为最狭义的类型的情况下,无法想出任何实际会导致不合理的东西。不过,也许你会觉得有趣
这里是一个具有类似约束的函数h
,但我们采用的是稍微不同的类型构造函数,而不是List
其主要思想是,Cc
有两个独立的类型参数:
- 第一个是在
F[\u]
- 第二个是与
trait Lst[+X]中的A
交互的
//定义性状
scala>case类Cc[+I,+X](I:I)扩展了Lst[X]
//已定义案例类别Cc
scala>类型T[+I]=Cc[I,无]
//定义的别名类型T[+I]=Cc[I,无]
scala>def h[F[]h(xs)
val res9:Cc[Int,Nothing]=Cc(42)
如果A
被推断为满足约束的最窄可能类型,那么为什么在第一种情况下当约束看起来相同时会推断Int?有什么区别?@MarioGalic我已经更新了答案以涵盖第一种情况。不知道是否足够清楚。在这两种情况下,最窄可能类型已经是infrred。@用户我认为两者都应该起作用。我不知道是否有区别。如果您发现一个只适用于1种情况的示例,可以让我知道。我认为这两种方法都适用于这种情况,但如果您想对as
执行操作,则需要使用下划线和通配符以外的内容。也就是说,F[x]@user我将添加这一点作为替代,然后这就是Scala编译器如何处理没有类型绑定的通配符类型参数。它将只推断为Any
。如果有类型绑定,它将类似于$1,其中xxxx@texasbruce在第一种情况下也没有类型绑定参数?在第一种情况下,F不是类型constr构造函数,但它是一个完整类型,是列表[a]的子类型。当您传递列表[Int]时,F在编译器中注册为列表[Int]。在类型构造函数的第二种情况下,编译器只注意到F是一个类型构造函数,它接受任何值(因为您传递了一个通配符)和列表[a](推断为列表[Int])更具体地说,您正试图将F[A](自动推断)返回为List[Int],因此A必须是Any。(在Scala2中失败)。在@yangai的回答中,F和List都使用Any,因此它也可以工作。@MarioGalic在第二种情况下,如果您显式地使A
anInt
类似于F[List,Int](List(42))
它不会编译。总之,在这两种情况下,推断的类型已经是可能的最窄类型。@texasbruce在第一种情况下,编译器能够解构正确的类型列表[Int]
为A
选择Int
,这在Scala 2中并非如此,因此它似乎比简单地将List[Int]
分配给F
更为重要。
(run in 3.0.0-RC2)
scala> trait Lst[+X]
// defined trait Lst
scala> case class Cc[+I, +X](i: I) extends Lst[X]
// defined case class Cc
scala> type T[+I] = Cc[I, Nothing]
// defined alias type T[+I] = Cc[I, Nothing]
scala> def h[F[_] <: Lst[A], A](as: F[A]) = as
def h[F[_$1] <: Lst[A], A](as: F[A]): F[A]
scala> val xs: T[Int] = Cc(42)
val xs: T[Int] = Cc(42)
scala> h(xs)
val res9: Cc[Int, Nothing] = Cc(42)