我正在创建一个带有lambda的函数,如果可能的话,使用.tupled
(arity 2+)。为了让编译器允许使用它,它需要知道lambda是否真的是一个Function2(〜Function22)。但是,Function2[Any,Any,Any]
的模式匹配意味着我留下了(Any, Any) => Any
而不是原始类型。甚至不知道arity也没有帮助。我尝试匹配case f[A <: Any, B <: Any, C <: Any]: scala.Function2[A, B, C] => f.tupled
以试图保留类型,但它并不真正允许案例的类型参数。
代码:
val add = (a: Int, b: Int) => a + b
add: (Int, Int) => Int = <function2>
val tpl = (fn: Any) => {
fn match {
case f: Function0[Any] => f
case f: Function1[Any,Any] => f
case f: Function2[Any,Any,Any] => f.tupled
// case f: Function3[Any,Any,Any,Any] => f.tupled
// ...
// case _ => { throw new Exception("huh") }
}
}
// actual result:
tpl(add)
res0: Any = <function1>
// desired result is like this one:
scala> add.tupled
res3: ((Int, Int)) => Int = <function1>
如果我不需要每个可能的arity级别的模式匹配案例,那么奖励积分......
答案 0 :(得分:1)
答案很难看,正如你所预料的那样。在函数上使用模式匹配作为val将不起作用。当您从Any
开始时,您已经丢失了大量的类型信息。并且标准库也没有真正帮助,因为没有功能的抽象。这意味着我们甚至不能真正使用反射来尝试获取类型参数,因为我们甚至不知道有多少参数。你可以弄清楚你有FunctionN
,但不是它包含的类型,因为它们已经丢失了。
另一种可能性是使tpl
成为一种方法,并为每个FunctionN
重载一次。
def tpl[A](f: Function0[A]): Function0[A] = f
def tpl[A, R](f: Function1[A, R]): Function1[A, R] = f
def tpl[A1, A2, R](f: Function2[A1, A2, R]): Function1[(A1, A2), R] = f.tupled
def tpl[A1, A2, A3, R](f: Function3[A1, A2, A3, R]): Function1[(A1, A2, A3), R] = f.tupled
// ... and so on
scala> val add = (a: Int, b: Int) => a + b
add: (Int, Int) => Int = <function2>
scala> tpl(add)
res0: ((Int, Int)) => Int = <function1>
它不漂亮,但它至少是类型安全的。我认为创建一个宏来生成重载1-22并不太难。