[英]Analogy between `F[_ <: A] <: B` at type-level and `f: A => B` at value-level
假设F[_ <: A] <: B
作为f: A => B
的类型级模拟,让[F[_ <: Int] <: List[Int], A <: Int]
,那么不应该type application F[A]
yield List[Int]
when A = Int
,所以f(List(42))
应该在以下情况下编译
$ scala3-repl
scala> def f[F[_ <: Int] <: List[Int], A <: Int](as: F[A]) = as
def f[F[_$1] <: List[Int], A <: Int](as: F[A]): F[A]
scala> f(List(42))
1 |f(List(42))
| ^^^^^^^^
|Found: List[Int]
|Required: F[A]
|
|where: A is a type variable with constraint <: Int
| F is a type variable with constraint <: [_$1 <: Int] =>> List[Int]
通过显式提供类型参数应用错误消息使其工作
scala> f[[_ <: Int] =>> List[Int], Int](List(42))
val res0: List[Int] = List(42)
类比在哪里中断? 考虑F[_ <: Int] <: List[Int]
作为从Int
到List[Int]
的类型级别 function 的我的心理 model 错在哪里?
首先,关于推断类型 lambdas,我认为类型推断不会 go 到提出类型 lambdas 只是为了满足约束的程度,否则直观上看起来一切都可以使用一些复杂的类型 lambda 进行类型检查,而这不会在拾取类型错误时很有用。
至于为什么f[List, Int](List(42))
无法编译(因此无法推断),我们需要参考 lambdas 类型的子类型规则:
假设有两种类型的 lambda
type TL1 = [X >: L1 <: U1] =>> R1 type TL2 = [X >: L2 <: U2] =>> R2
那么
TL1 <: TL2
,如果
- 类型区间
L2..U2
包含在类型区间L1..U1
(即L1 <: L2
和U2 <: U1
),R1 <: R2
另请注意:
部分应用的类型构造函数(例如
List
)被假定为等效于它的 eta 扩展。 即,List = [X] =>> List[X]
。 这允许将类型构造函数与类型 lambda 进行比较。
这意味着所有这些都将编译:
f[[_ <: Int] =>> List[Int], Int](List(42)) //author's compiler example
f[[_] =>> List[Int], Int](List(42)) //input type bounds can be wider, output stays the same
f[[_] =>> List[42], Int](List(42)) //input wider, output narrower
f[[x <: Int] =>> List[x], Int](List(42))//input same, output narrower
所有这些都不会:
f[[x] =>> List[x], Int](List(42)) //input type bounds can be wider but in this case it will also make the output wider
f[List, Int](List(42)) //equivalent to preceding case
f[[_ <: 42] =>> List[Int], Int](List(42)) //input type bounds cannot be narrower
如果是:
def f[F[x] <: List[x], A <: Int](as: F[A]) = as
如果您从同一类型 lambda 角度查看它f[[x] =>> List[x], Int](List(42))
应该可以工作,因此f[List, Int](List(42))
也可以编译(并被推断)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.