如何将泛型方法转换为泛型函数

时间:2019-11-18 22:36:33

标签: scala generics polymorphic-functions

问题

如何将定时方法转换为函数?

val timing = new StringBuffer
def timed[T](label: String, code: => T): T = {
  val start = System.currentTimeMillis()
  val result = code
  val stop = System.currentTimeMillis()
  timing.append(s"Processing $label took ${stop - start} ms.\n")
  result
}

以下导致“错误:未找到:键入T”

val timing = new StringBuffer
val timed: (String, => T) => T = (label, code) => {
    val start = System.currentTimeMillis()
    val result = code
    val stop = System.currentTimeMillis()
    timing.append(s"Processing $label took ${stop - start} ms.\n")
    result
}

2 个答案:

答案 0 :(得分:3)

Scala中没有泛型函数(根本没有泛型值),只有泛型方法。

通用函数将出现在Scala 3中。

https://github.com/lampepfl/dotty/pull/4672

http://dotty.epfl.ch/docs/reference/overview.html#new-constructs

val timing = new StringBuffer
val timed: [T] => (String, /*=>*/ T) => T = [T] => (label: String, code: /*=>*/ T) => {
  val start = System.currentTimeMillis()
  val result = code
  val stop = System.currentTimeMillis()
  timing.append(s"Processing $label took ${stop - start} ms.\n")
  result
}

在Dotty 0.20.0-RC1中。

答案 1 :(得分:3)

Scala没有多态功能。

让我使用Miles Sabin的excellent blog post中的示例:

def singleton[T](t: T) = Set(t)

// eta-expanded to Int => Set[Int]
List(1, 2, 3) map singleton

// eta-expanded to String => Set[String]
List("foo", "bar", "baz") map singleton

方法singleton()在使用时将eta-expanded放入函数中,并在那时将其类型固定为推断的具体类型。因此它可以轻松地“变成”(扩展为)函数Int => Set[Int]String => Set[String],但不能停留在T => Set[T]之类的位置。语言本身没有内置的方式来表达多态函数(Scala 3 might change that)。

但是,有一种方法可以通过自然变换和/或shapelessPoly和一些类型的体操来具有多态功能。两者都基于相同的原理,即将函数编码为具有较高类型的输入/输出特征的特征,并具有通用的apply[T]()方法和独立类型T,每个独立类型都固定为不同的具体类型函数被调用的时间(在我们的示例中为IntString等)。

类似这样的东西:

trait PolymorphicFunction[F[_], G[_]] {
  def apply[T](f: F[T]): G[T]
}

但是,与其在这里尝试进行详细说明,不如将您引荐给无形的documentation和上述简短的博客文章系列。