函数调用返回的元组没有中间值

时间:2017-06-16 07:03:09

标签: scala

我在scala中有一个返回元组的函数:

private def someFunction(from: List[Any], to: List[Any]): (List[Any], List[Any]) = {
   // Do some stuff
   (modifiedFrom, modifiedTo)
}

我想分解该元组,并将值作为参数传递给另一个函数:

@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)
}

是否可以改写:

someOtherFunction(one, someFunction(foo,bar)) // This is a compile error.

我能以更干净的方式编写分解吗?

3 个答案:

答案 0 :(得分:3)

不太漂亮(scala想要类型归属),但如果你真的想要单行:

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

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

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

说明:

  • tupled是为每个Function实例定义的方法(作为一等公民lambda)。它返回一个可以接受元组的函数。

  • f2(1, _: Int, _: Int)是一个部分应用程序 - 它在这里从第二个和第三个参数返回一个函数,所以之后它可以被“tupled”

P.S。您可以通过将f2重新定义为:

来避免类型归因丑陋
def f2(a: Int)(b: Int, c: Int) = 0
f2(1) _ tupled f1()

更新。如果您不想打破尾递归,请使用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

此处的另一个好处是,如果f2变得更复杂 - 在代码中跟踪尾部调用会更容易。它还支持相互尾递归等功能。

说明:

  • tailcall标记了一个尾递归调用
  • done标记您希望在循环结束时返回的值
  • .result运行堆栈安全计算并从TailCall[T]中提取结果。您还可以注意到TailCall包装器向@tailrec播放simillar角色 - 它不允许非尾部定位调用,因为它需要“解包”结果。编译器级优化正在被蹦床计算所取代,这也是堆栈安全的。

答案 1 :(得分:2)

我认为没有更清洁的方法。也许有可能使用宏来做某事,但它有点挫败了目的。

只有我能想到的替代品(有点清洁,因为它不会污染命名空间)如下:

REST

答案 2 :(得分:2)

如果使用两个参数组定义了someOtherFunction,那么它很容易。

而不是......

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

......你可以这样做。

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

但是,你可能不得不将元组分解为其部分。