user1052610
user1052610

Reputation: 4719

Passing a tuple to a curried function

The following tuple:

val i = (1, 2, 3, 4, 5, 6)

needs to be passed as a parameter to a curried function, as follows:

f("param") (i)

When defining the curried function, what is the correct way to define the type of the parameter which receives the tuple?

def f(s:String) (myTuple:???) = {
  val (a, b, c, d, e. f) = myTuple
  // more code
}

I want to avoid having the specify the number and type of each elememt in the tuple when defining the parameter type. In other words, I want to avoid this:

def f(s:String) (myTuple:(Int, Int, Int, Int, Int, Int)) = {
  val (a, b, c, d, e. f) = myTuple
  // more code
}

Thanks

Upvotes: 1

Views: 529

Answers (1)

Giovanni Caporaletti
Giovanni Caporaletti

Reputation: 5546

val i = (1, 2, 3, 4, 5, 6)

def f(s:String)(myTuple: (Int, Int, Int, Int, Int, Int)) = {
  val (a, b, c, d, e, f) = myTuple
}

f("param")(i)

Currying doesn't change the way you declare function parameters anyway:

val i = (1, 2, 3, 4, 5, 6)

def f(myTuple: (Int, Int, Int, Int, Int, Int)) = {
  val (a, b, c, d, e, f) = myTuple
}

f(i)

Since you have six parameters, I suggest you use a case class to document their meaning:

case class Params(p1: Int, p2: Int, someFancyName: Int, otherName: Int, p5: Int, p6: Int)

def f(myTuple: Params) = {
  val Params(a, b, c, d, e, f) = myTuple
}

val i = (1, 2, 3, 4, 5, 6)

f(Params.tupled(i))

your function parameter will be understood more easily from whoever calls it because each parameter has a name in the case class

I see you edited your question: if you want to avoid specifying the number of elements you can use something like the magnet pattern and implement a magnet for each tuple, or you can use macros.

If you use the magnet pattern, you will have to implement a number of different implementations, depending on the number and type of arguments (you can't be generic in your implementation, you have to know what to do with your arguments). This is a short example for tuples up to three items:

abstract class TupleMagnet[T](t: T) {
  def apply(): Unit
}

object TupleMagnet {
  implicit def tuple1Magnet[A](t: Tuple1[A]) = new TupleMagnet(t) {
    def apply() =  { println(t._1) }
  }
  implicit def tuple2Magnet[A, B](t: (A, B)) = new TupleMagnet(t) {
    def apply() = t match { case (a, b) =>  println(""+a + b) }

  }
  implicit def tuple3Magnet[A, B, C](t: (A, B, C)) = new TupleMagnet(t) {
    def apply() = t match { case (a, b, c) =>  println(""+a + b + c) }
  }
}


def f[T](magnet: TupleMagnet[T]) = magnet()

val i = (1, 2, 3)
f(i)

val j = (1, 2)
f(j)

Another option to be generic in the number/type of parameters could be using shapeless HLists or Records and implementing a Polymorphic function value or something similar.

Upvotes: 4

Related Questions