Variable number of types based on

I create a simple cache line (to easily cache my functions):

trait Cache[A,B] {
  def _calc(v:A):B
  private var cache = Map[A,B]()
  def calc(v:A):B = {
    cache.get(v) match {
      case Some(x) => x
      case None => 
        val x = _calc(v)
        cache += (v -> x)
        x
    }
  }
}

Using:

object Sol extends Cache[Int,Int] {
  def _calc(v:Int):Int = { /* do something here */ }
}
Sol.calc(5)

It works correctly, but the problem arises when I need to cache functions with a large number of arguments - therefore I need to develop features of Cache2, Cache3, all copies of the code in the first value.

A possible workaround is to convert functions with multiple arguments to functions that take a tuple, but that doesn't seem right.

Is there a way to do this more generally and to avoid violating DRY rules ?

+5
source share
4 answers

, (, add), :

object Add extends Cache[(Int, Int),Int]{
    def add (a:Int,b:Int):Int = a+b
    def _calc(t:(Int, Int)) = add _ tupled t
}

Add.calc(3, 5)

: Cache2... CacheN .

trait Cache2[A, B, C] extends Cache [(A,B), C] {
    def _calc2(a: A, b: B):C
    def _calc(t:(A,B)) = _calc2 _ tupled t
}

object Add2 extends Cache2[Int,Int,Int] {
    def _calc2(a:Int, b:Int) = a+b
}

Add2.calc(3, 5)

+1

script scala .

, scala TupleN, ProductN FunctionN ( N - int 21).

+3

- varargs calc:

trait Cache[A,B] {
  def _calc(v:A*):B
  private var cache = Map[Seq[A],B]()
  def calc(v:A*):B = {
    cache.get(v.toList) match {
      case Some(x) => x
      case None => 
      val x = _calc(v:_*)
      cache += (v -> x)
      x
      }
   }
 }

object Sol1 extends Cache[Int,Int] {
  def _calc(v:Int*):Int = {
    require(v.length<2 && v.length>0, "use Sol2 for two-argument functions")
    v.head
  }
}
object Sol2 extends Cache[Int,(Int,Int)] {
  def _calc(v:Int*):(Int,Int) = {
    require(v.length<3 && v.length>1, "use Sol1 for single-argument functions")
    (v.head,v.last)
  }
}

, .

+1

, , , , -, . memoization, . , FunctionDecorator:

trait FunctionDecorator {
   final def apply[T, R, F](f: F)(implicit e: Tupler[F, T => R]): F = 
      e.untupled(decorate(e.tupled(f)))

   protected def decorate[T, R](f: T => R): T => R
}

(, Memoize) , , , , .

Of course, this translates your DRY problem into the definition of Tuplers for all types of functions. I would suggest a paradigmatic sentence and use a script to define Tuplers. Tuplers are much more useful than a bunch of CacheN types.

+1
source

All Articles