Reputation: 22125
I have a function in scala that returns a tuple:
private def someFunction(from: List[Any], to: List[Any]): (List[Any], List[Any]) = {
// Do some stuff
(modifiedFrom, modifiedTo)
}
I want to decompose that tuple, and pass the values as parameters to another function:
@tailrec
someOtherFunction(first: List[Any], second: List[Any], third: List[Any]): Unit = {
// Some more stuff
val (two, three) = someFunction(foo, bar)
someOtherFunction(one, two, three)
}
Is it possible to instead write something like:
someOtherFunction(one, someFunction(foo,bar)) // This is a compile error.
Can I write the decomposition in a cleaner way?
Upvotes: 2
Views: 79
Reputation: 22374
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 calldone
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.Upvotes: 3
Reputation: 51271
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.
Upvotes: 2
Reputation: 10882
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)
}
Upvotes: 2