依赖函数类型 - 更多细节
初始实现位于 PR #3464 中。
语法
FunArgTypes ::= InfixType
| ‘(’ [ FunArgType {',' FunArgType } ] ‘)’
| ‘(’ TypedFunParam {',' TypedFunParam } ‘)’
TypedFunParam ::= id ‘:’ Type
依赖函数类型向右结合,例如 (s: S) => (t: T) => U
等同于 (s: S) => ((t: T) => U)
。
实现
依赖函数类型是定义了具有依赖结果类型的 apply
方法的类类型的简写。依赖函数类型反糖化为 scala.FunctionN
的细化类型。一个 N
元的依赖函数类型 (x1: K1, ..., xN: KN) => R
转换为
FunctionN[K1, ..., Kn, R']:
def apply(x1: K1, ..., xN: KN): R
其中结果类型参数 R'
是精确结果类型 R
的最小上界近似值,不包含对值参数 x1, ..., xN
的任何引用。
匿名依赖函数的语法和语义与普通函数相同。eta 扩展自然地推广到为具有依赖结果类型的方法生成依赖函数类型。
依赖函数可以是隐式的,并且与其他函数一样,可以推广到 N > 22
的元数,参见 相关文档。
示例
以下示例定义了一个特征 C
和两个依赖函数类型 DF
和 IDF
,并打印了相应函数应用的结果
trait C { type M; val m: M }
type DF = (x: C) => x.M
type IDF = (x: C) ?=> x.M
@main def test =
val c = new C { type M = Int; val m = 3 }
val depfun: DF = (x: C) => x.m
val t = depfun(c)
println(s"t=$t") // prints "t=3"
val idepfun: IDF = summon[C].m
val u = idepfun(using c)
println(s"u=$u") // prints "u=3"
在以下示例中,依赖类型 f.Eff
指的是效果类型 CanThrow
trait Effect
// Type X => Y
abstract class Fun[-X, +Y]:
type Eff <: Effect
def apply(x: X): Eff ?=> Y
class CanThrow extends Effect
class CanIO extends Effect
given ct: CanThrow = new CanThrow
given ci: CanIO = new CanIO
class I2S extends Fun[Int, String]:
type Eff = CanThrow
def apply(x: Int) = x.toString
class S2I extends Fun[String, Int]:
type Eff = CanIO
def apply(x: String) = x.length
// def map(f: A => B)(xs: List[A]): List[B]
def map[A, B](f: Fun[A, B])(xs: List[A]): f.Eff ?=> List[B] =
xs.map(f.apply)
// def mapFn[A, B]: (A => B) -> List[A] -> List[B]
def mapFn[A, B]: (f: Fun[A, B]) => List[A] => f.Eff ?=> List[B] =
f => xs => map(f)(xs)
// def compose(f: A => B)(g: B => C)(x: A): C
def compose[A, B, C](f: Fun[A, B])(g: Fun[B, C])(x: A):
f.Eff ?=> g.Eff ?=> C =
g(f(x))
// def composeFn: (A => B) -> (B => C) -> A -> C
def composeFn[A, B, C]:
(f: Fun[A, B]) => (g: Fun[B, C]) => A => f.Eff ?=> g.Eff ?=> C =
f => g => x => compose(f)(g)(x)
@main def test =
val i2s = new I2S
val s2i = new S2I
assert(mapFn(i2s)(List(1, 2, 3)).mkString == "123")
assert(composeFn(i2s)(s2i)(22) == 2)
类型检查
反糖化后,依赖函数类型不需要额外的类型规则。
本文档