0

假设作为, letF[_ <: A] <: B的类型级模拟,则不应键入 application yield when ,因此应在以下情况下编译f: A => B[F[_ <: Int] <: List[Int], A <: Int]F[A]List[Int]A = Intf(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]类型级别函数的心智模型在哪里?IntList[Int]

4

1 回答 1

1

首先关于推断类型 lambda,我认为类型推断不会达到仅仅为了满足约束而提出类型 lambda 的程度,否则直观上看起来一切都可以使用一些复杂的类型 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 <: L2U2 <: 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))也可以编译(并被推断)。

于 2021-04-12T15:54:26.360 回答