scala - 如何在 scala 中使用泛型创建部分函数?

标签 scala anonymous-function currying

我正在尝试为 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函数直接起作用,编译器正确使用匿名函数的返回类型来键入“时间”函数:
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("-")
    

    如果我内联柯里化(Currying),我会得到同样的错误:
    val timerBigString = time('timerBigString) _ 
    val bigString = timerBigString  {
        (1 to 100000).mkString("-")
    }
    println (bigString)
    

    如果我这样做 val timerBigString = time('timerBigString) (_: String) 就可以了,但这不是我想要的。我想将部分应用函数的输入推迟到应用程序。

    我的结论是,当我第一次创建部分函数时,编译器正在决定它的返回类型,选择“Nothing”,因为它无法做出更明智的选择。

    所以我想我正在寻找的是一种部分应用函数的后期绑定(bind)。有没有办法做到这一点?或者也许我可以走一条完全不同的道路?

    好吧,谢谢你读到这里

    -teo

    最佳答案

    当您想要“惰性”泛型时,通常的模式是使用带有 apply 方法的类

    class Timer(name: Symbol) {
      def apply[T](op: => T) = time(name)(op)
    }
    def mkTimer(name: Symbol) = new Timer(name)
    

    关于scala - 如何在 scala 中使用泛型创建部分函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4646894/

    相关文章:

    Scala 2.8 正确处理 Boolean 和 java.lang.Boolean 吗?

    部分模型的Scala成语?

    java - 如何从 Play Framework 中的另一个模板调用一个模板?

    javascript - javascript中的闭包和匿名函数

    javascript - 这个函数如何获取索引值呢?

    javascript - 直接调用匿名函数与通过变量调用之间的区别?

    ocaml - 为什么 "currying"要求很重要?

    scala - 计算scala中过滤的记录

    柯里化(Currying)和编译器设计