如何在Scala中定义一个函数myEval(f, args)
,它将另一个函数f
和参数args
作为输入,其输出为f(args)
?
我不希望myEval
对f
的arity或参数类型有任何先验知识。
为什么这有用?这是解决实现通用timeMyFunction(f, args)
方法问题的一种方法。如果有一种方法可以通过某种懒惰的val构造来实现这一点,那也很有趣。
编辑:this question中介绍了实施计时方法的更好方法。通过调用timeMyFunction( { f(args) } )
,函数调用包含在匿名函数Unit => Unit
中。所以timeMyFunction
只需要采用0-arity函数。
编辑2 :请参阅Dirk的回答,了解可能是一种更有效的方法,可以通过引用传递f
来避免匿名函数。
所以我对这个问题的理由现在纯粹是我的Scala教育。
答案 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
本身需要实际值时。
由于“按名称传递”惯例的开销,此变体可能会引入一些定时噪声。