Как мне создать частичную функцию с универсальными шаблонами в scala?

Я пытаюсь написать библиотеку измерения производительности для Scala. Моя идея состоит в том, чтобы прозрачно «отмечать» разделы, чтобы можно было собирать время выполнения. К сожалению, мне не удалось подчинить компилятор своей воле.

По общему признанию, надуманный пример того, что я имел в виду:

// generate a timing function
val myTimer = mkTimer('myTimer) 

// see how the timing function returns the right type depending on the
// type of the function it is passed to it
val act = actor {
    loop { 
        receive {

            case 'Int =>
                val calc = myTimer { (1 to 100000).sum }
                val result = calc + 10 // calc must be Int
                self reply (result)

            case 'String =>
                val calc = myTimer { (1 to 100000).mkString }
                val result = calc + " String" // calc must be String
                self reply (result)
}

Это самое дальнее, что я получил:

trait Timing {
   def time[T <: Any](name: Symbol)(op: => T) :T = {
      val start = System.nanoTime
      val result = op
      val elapsed = System.nanoTime - start
      println(name + ": " + elapsed) 
      result
  }

  def mkTimer[T <: Any](name: Symbol) : (() => T) => () => T = {
      type c = () => T
      time(name)(_ : c)
  }
}

Использование функции time работает напрямую, и компилятор правильно использует возвращаемый тип анонимной функции для ввода функции 'time':

val bigString = time('timerBigString) {
    (1 to 100000).mkString("-")
}
println (bigString)

Каким бы замечательным это ни казалось, этот шаблон имеет ряд недостатков:

  • вынуждает пользователя повторно использовать один и тот же символ при каждом вызове
  • , что затрудняет выполнение более сложных вещей, таких как предопределенные таймеры уровня проекта
  • не разрешить библиотеке инициализировать однажды структуру данных для 'timerBigString

Итак, здесь идет mkTimer, который позволит мне частично применить функцию времени и повторно использовать ее. Я использую mkTimer следующим образом:

val myTimer = mkTimer('aTimer)
val myString= myTimer {
    (1 to 100000).mkString("-")
}
println (myString)

Но я получаю ошибку компилятора:

error: type mismatch;
found   : String
required: () => Nothing
(1 to 100000).mkString("-")

Я получаю ту же ошибку, если встраиваю каррирование:

val timerBigString = time('timerBigString) _ 
val bigString = timerBigString  {
    (1 to 100000).mkString("-")
}
println (bigString)

Это работает, если я выполняю val timerBigString = time ('timerBigString) ( _: Строка) , но я не этого хочу. Я хотел бы отложить ввод частично примененной функции до приложения.

Я пришел к выводу, что компилятор определяет тип возвращаемого значения частичной функции, когда я впервые ее создаю, выбирая «Ничего», потому что это не может улучшить осознанный выбор.

Итак, я предполагаю, что я ищу своего рода позднюю привязку частично примененной функции. Есть какой-либо способ сделать это? Или, может быть, я мог бы пойти по совершенно другому пути?

Что ж, спасибо, что дочитали до этого места

-teo

7
задан Craig P. Motlin 24 January 2011 в 13:02
поделиться