HOME | EDIT | RSS | INDEX | ABOUT | GITHUB

Scala 3 从属类型

中文 | English


可以跑的源码在这里 👉 https://github.com/jcouyang/meow


Scala 2

如果经常使用 Shapeless, 你可能会熟悉一种叫 Aux 的 Pattern 这个pattern经常用来推倒输出类型

比如:

trait Second[L <: HList] {
  type Out
  def apply(value: L): Out
}

object Second {
  type Aux[L <: HList, O] = Second[L] { type Out = O }

  def apply[L <: HList](implicit inst: Second[L]): Aux[L, inst.Out] =
    inst
}

Second(1 :: "2" :: HNil)

输出:

"2"

可以看见这个 Second 是 dependent types, 也就是说他的类型取决于输入的类型, 比如现在换一个 HList,他的 输出就不是 String 了:

Second("1" :: 2 :: HNil)
// => 2

输入变成 Int 了。

Scala 3

在 Scala 3 我们不仅可以用dependent methods,还可以声明 dependent function https://dotty.epfl.ch/docs/reference/new-types/dependent-function-types.html 。 也就是上面那个例子,可以进一步的简化:

trait Second[L <: HList] {
  type Out
  def apply(value: L): Out
}

object Second {
  def apply[L <: HList](value: L) = (inst: Second[L]) ?=> inst(value)
}

其中 ?=> https://dotty.epfl.ch/docs/reference/contextual/context-bounds.html 里面的问号并不是我的typo,这是简写的 (using inst: Second[L]) => inst(value)

注意看前后的区别:

- def apply[L <: HList](implicit inst: Second[L]): Aux[L, inst.Out] =
    inst
+ def apply[L <: HList](value: L) = (inst: Second[L]) ?=> inst(value)

以前需要标明method类型为dependent types Aux[L, inst.Out]

现在你看,我们可以把 Aux 和 Out 消除掉,因为你可以直接返回一个 dependent function

如果你给这个 dependent function 标类型的话:

def apply[L <: HList](value: L): (inst: Second[L]) ?=> inst.Out =
 (inst: Second[L]) ?=> inst(value)

它就跟Scala 2 dependent method的时候很像了,但是我们还是不用 Aux 类型的帮助。

如果懒得拉源代码下来玩,可以在 scastie 上试试 https://scastie.scala-lang.org/fyxXSR3ASj6rSkkERnUK7g

Footnotes: