[英]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.