Function with any number of arguments as parameter

不打扰是莪最后的温柔 提交于 2019-12-25 06:43:11

问题


I have method eval which takes List of Function and arguments, currently I am writing case for every possible function. How can I write it more generic?

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:


You could write something like this using shapeless, which has the benefit that it is type safe and checked at compile time (compared with using Any in your 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)
}

Which you could use as :

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

You can also use it with a case class if it follows the same format (first a function then the right arguments for that function) :

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


来源:https://stackoverflow.com/questions/33303520/function-with-any-number-of-arguments-as-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!