Scala: How to define a function whose input is (f, args) and whose output is f(args)?

generics, lazy-evaluation, scala

Solution

The Scala standard library isn't going to help you generalize over arity in most cases, but Shapeless is perfect for this. Here's how you could write your function in 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))

And then:

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

It looks complicated, but essentially you're just saying that you need evidence that a function `f` of some arbitrary arity can be converted to a single-argument function from a heterogeneous list `A` to the result `R`, and that the tuple `P` can be converted to a heterogeneous list of the same type.

Problem

How can you define a function `myEval(f, args)` in Scala which takes as input another function `f` and arguments `args` and whose output is `f(args)`? I don't want `myEval` to have any prior knowledge about the arity or argument types of `f`. Why is this useful? It is one way to solve the problem of implementing a generic `timeMyFunction(f, args)` method. If there's a way to do this by some sort of lazy val construction, that would also be interesting. Edit: The better way to implement a timing method is explained in this question. By calling `timeMyFunction( { f(args) } )`, the function call is wrapped in an anonymous function `Unit => Unit`. So `timeMyFunction` only needs to take 0-arity functions. Edit 2: See Dirk's answer for what is perhaps a more efficient way which avoids an anonymous function by passing `f` by reference. So my justification for the question is now purely my Scala education.

Original source

Related problems