Как преобразовать универсальный метод в универсальную функцию
Вопрос
Как преобразовать метод, рассчитанный по времени, в функцию?
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 ответа
В Scala нет такой вещи, как универсальная функция (и вообще универсального значения), есть только универсальные методы.
Стандартные функции появятся в Scala 3.
https://github.com/lampepfl/dotty/pull/4672
http://dotty.epfl.ch/docs/reference/overview.html
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.
В Scala нет полиморфных функций.
Позвольте мне использовать пример из отличного сообщения в блоге Майлза Сабина:
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()
получает ет вспененную в функцию в точке использования, и в этот момент его типы фиксируются в выведенные тип бетона. Таким образом, он может легко "стать" (быть расширен) функциейInt => Set[Int]
или String => Set[String]
, но не может оставаться что-то вроде T => Set[T]
. В самом языке нет встроенного способа выражения полиморфных функций (Scala 3 может это изменить).
Тем не менее, есть способ, чтобы иметь полиморфные функции через естественные преобразования и / или бесформенные-хPoly
с немного типовой гимнастикой. Оба основаны на одном и том же принципе кодирования функции как признака с более высокими типами для ввода / вывода и имеющими общийapply[T]()
метод с независимым типом T
который фиксируется к другому конкретному типу каждый раз при вызове функции (в нашем случае это были бы Int
, String
так далее.).
Что-то вроде этого:
trait PolymorphicFunction[F[_], G[_]] {
def apply[T](f: F[T]): G[T]
}
Но вместо того, чтобы пытаться подробно объяснить это здесь, я бы предпочел отослать вас к бесформенной документации и вышеупомянутой короткой серии сообщений в блогах.