score:3

Accepted answer

Not so pretty (scala wanted type ascription), but if you really want one-liner:

def f1(): (Int, Int) = (2,3)

def f2(a: Int, b: Int, c: Int) = 0

(f2(1, _: Int, _: Int)).tupled(f1())

Explanation:

  • tupled is a method defined for every Function instance (as first-class citizen lambda). It returns a function that can accept tuples.

  • f2(1, _: Int, _: Int) is a partial application - it returns a function from second and third argument here, so it could be "tupled" afterwards

P.S. You could avoid type-ascription ugliness, by redefining f2 as:

def f2(a: Int)(b: Int, c: Int) = 0
f2(1) _ tupled f1()

Update. If you don't want to break tail-recursion, use TailCalls:

import scala.util.control.TailCalls._
def f2(a: Int)(b: Int, c: Int): TailRec[Int] = 
  if (false) tailcall(f2(1) _ tupled f1()) else done(0)

f2(1)(2, 3).result

The additional advantage here is that if your f2 gets more complex - it's easier to trace tail-positioned calls in the code. It also supports things like mutual tail-recursion.

Explanation:

  • tailcall marks a tail-recursive call
  • done marks value you want to return in the end of loop
  • .result runs stack-safe computation and extracts result from TailCall[T]. You can also notice that TailCall wrapper plays simillar role to @tailrec - it doesn't allow non-tail-positioned call, as it would require to "unwrap" the result. Compiler-level optimization is being replaced by trampolined computation, which is also stack-safe.

score:2

I don't think that there is a cleaner way out of box. Perhaps it's possible to do something using macros, but it kinda defeats the purpose.

Only alternative I can think of (sort of cleaner, because it doesn't pollute the namespace) is following:

someFunction(foo, bar) match {
  case (two, three) => someOtherFunction(one, two, three)
}

score:2

If someOtherFunction were defined with two parameter groups then it'd be easy.

Instead of this ...

val (two, three) = someFunction(foo, bar)
someOtherFunction(one)(two, three)

... you could do this.

someOtherFunction(one) _ tupled someFunction(foo, bar)

But short of that you'll probably have to break the tuple into its parts.


Related Query