具有任意数量参数的函数作为参数

时间:2015-10-23 13:27:05

标签: scala functional-programming

我有方法eval,它接受函数列表和参数,目前我正在为每个可能的函数编写案例。我怎么能写得更通用呢?

implicit class Expression(p: Product) {
  def eval = p.productIterator.toList match {
    case (f: ((Any) => Any)) :: p1 :: Nil => f(p1)
    case (f: ((Any, Any) => Any)) :: p1 :: p2 :: Nil => f(p1, p2)
    case (f: ((Any, Any, Any) => Any)) :: p1 :: p2 :: p3 :: Nil => f(p1, p2, p3)
  }
}
def print = (x: Any) => println(">> " + x)
def add = (x: Any, y: Any) => x.asInstanceOf[Int] + y.asInstanceOf[Int]
(print, "test").eval
(add, 2, 3).eval

1 个答案:

答案 0 :(得分:3)

你可以使用shapeless编写这样的东西,这样做的好处是类型安全并在编译时检查(与在Any中使用Expression.eval相比)。

import shapeless._
import ops.hlist._
import syntax.std.function._
import ops.function._

def eval[P <: Product, G <: HList, F, L <: HList, R](
  p: P
)(implicit 
  gen: Generic.Aux[P, G], 
  ihc: IsHCons.Aux[G, F, L], 
  ftp: FnToProduct.Aux[F, L => R]
) = { 
  val l = gen.to(p)
  val (func, args) = (l.head, l.tail)
  func.toProduct(args)
}

您可以将其用作:

def add(a: Int, b: Int) = a + b
val stringLength: String => Int = _.length

eval((add _, 1, 2))             // Int = 3
eval((stringLength, "foobar"))  // Int = 6
eval((stringLength, 4))         // does not compile

如果它遵循相同的格式(首先是函数,然后是该函数的右参数),您也可以将它与案例类一起使用:

case class Operation(f: (Int, Int) => Int, a: Int, b: Int)
eval(Operation(_ + _, 1, 2))    // Int = 3
eval(Operation(_ * _, 1, 2))    // Int = 2
相关问题