在 GitHub 上編輯此頁面

依賴函數類型 - 更多詳細資訊

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 和兩個依賴函數類型 DFIDF,並列印各個函數應用程式的結果

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)

類型檢查

在去糖化之後,依賴函數類型不需要額外的類型規則。