Scala:如何定义一个输入为(f,args)且输出为f(args)的函数?

时间:2014-04-15 09:52:26

标签: scala generics lazy-evaluation

如何在Scala中定义一个函数myEval(f, args),它将另一个函数f和参数args作为输入,其输出为f(args)

我不希望myEvalf的arity或参数类型有任何先验知识。

为什么这有用?这是解决实现通用timeMyFunction(f, args)方法问题的一种方法。如果有一种方法可以通过某种懒惰的val构造来实现这一点,那也很有趣。

编辑this question中介绍了实施计时方法的更好方法。通过调用timeMyFunction( { f(args) } ),函数调用包含在匿名函数Unit => Unit中。所以timeMyFunction只需要采用0-arity函数。

编辑2 :请参阅Dirk的回答,了解可能是一种更有效的方法,可以通过引用传递f来避免匿名函数。

所以我对这个问题的理由现在纯粹是我的Scala教育。

2 个答案:

答案 0 :(得分:9)

在大多数情况下,Scala标准库不会帮助您对arity进行概括,但Shapeless非常适合这种情况。以下是在Shapeless 1.2.4中编写函数的方法:

import shapeless._

def foo[F, P <: Product, A <: HList, R](f: F, p: P)(implicit
  fl: FnHListerAux[F, A => R],
  pl: HListerAux[P, A]
): R = fl(f)(pl(p))

然后:

scala> foo((i: Int, s: String) => s * i, (3, "a"))
res0: String = aaa

它看起来很复杂,但基本上你只是说你需要证据证明某个任意arity的函数f可以从异构列表A转换为单个参数函数结果R,并且元组P可以转换为相同类型的异构列表。

答案 1 :(得分:1)

使用pass-by-name的替代方法是:

def timeIt[T](thunk: =>T): T = {
    // ... set-up the timer 
    val answer: T = thunk
    // ... evaluate the result of the timer
    answer  // in case, you need the result and want the timing to
}           // happen just as a side-effect

timeIt(someFunction(someArg1, ...))

虽然这看起来好像会直接调用someFunction,但它没有,因为timeIt接受“按名称”的参数,即scala编译器生成一个隐藏的闭包,它执行调用,当timeIt本身需要实际值时。

由于“按名称传递”惯例的开销,此变体可能会引入一些定时噪声。