1

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
Wieloming
  • 23
  • 3
  • Possible duplicate of ['Spread' parameters in Scala?](http://stackoverflow.com/questions/15170646/spread-parameters-in-scala) – Bergi Oct 23 '15 at 13:39

1 Answers1

4

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
Peter Neyens
  • 9,770
  • 27
  • 33
  • Could you show me also a way to implement it without shapeless and type safety, I am just really curious is it possible to do it in simpler way? – Wieloming Oct 23 '15 at 15:54
  • Generic programming like this with abstraction over function arity and the argument types is not possible in Scala without shapeless. – Peter Neyens Oct 23 '15 at 16:06
  • Is there a way to constrain the possible arguments, for example, only allow `Option[_]`? – steinybot Aug 13 '21 at 04:18