7

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.

5
  • Not much an answer, but usually timeMyFunction is written in a bit different way (and yes, it will work for functions with arbitrary arity) Commented Apr 15, 2014 at 9:58
  • My attempts at writing a timeMyFunction were based off the link you post, but you have to make a different version for every arity, at least in my naive way of doing it. Commented Apr 15, 2014 at 10:29
  • 1
    No, you don't Commented Apr 15, 2014 at 10:33
  • instead of specifying function and arguments for it, you should provide a whole block(e.g: instead of timeMyFunction(f, args), timeMyFunction(f(args)) where timeMyFunction signature is as in the link provided by om-nom-nom) Commented Apr 15, 2014 at 10:35
  • Thanks! So it looks like I am wrapping f in an anonymous function which takes no arguments, and then I can use the time function. Commented Apr 15, 2014 at 10:40

2 Answers 2

9

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.

Sign up to request clarification or add additional context in comments.

3 Comments

It makes sense, and the shapeless library looks very powerful, but I don't see why Scala doesn't consider the arguments of a function to be a tuple, e.g., that all functions have type Function[Tuple]?
Yep, that's a good question. I wish Scala had followed OCaml, Haskell, etc. in that respect.
@expz: Unifying parameter lists and tuples has been an Martin Odersky's wish list for a long time, but it is a) low priority and b) very hard to pull off in a way that is both backwards-compatible and doesn't hurt platform integration. For example, how would Java see an overloaded Scala method, if all overloads just take a tuple?
1

An alternative using pass-by-name would be:

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, ...))

Though this looks as if it would call someFunction directly, it does not, since timeIt takes the argument "by name", i.e., the scala compiler generates a hidden closure, which performs the call, when the actual value is needed in timeIt itself.

This variant may introduce some timing noise due to the overhead of the "pass-by-name" convention.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.