Create a collection of functions tupled with a collection of parameters, and execute the collection in order in Scala I am trying to create a collection of Unit functions that have any arity and type, and will execute them in order.

This is the working implementation that I have:

/** A Subroutine simply represents a unit function that takes any number of parameters. */
type Subroutine = (Any) =&gt; Unit

/** A Routine represents a collection of functions which may consume a collection of parameters and will always
  * complete an action.
  */
type Routine = List[(Subroutine, Seq[_])]

/** This function will consume a list of functions executing them in order.
  *
  * @param routine is the list of functions and their parameters to be consumed.
  */
def executeRoutine(routine: Routine): Unit = {
  routine.headOption match {
    case Some((f, x)) =&gt;
      f(x)
      executeRoutine(routine.tail)
    case None =&gt; ()
  }
}


and when I declare a function or "subroutine", I have to declare it like this in order to extract the parameters:

def myFunction: Subroutine = {
  case (firstParam: Int) :: (secondParam: String) :: _ =&gt; ...
  case _ =&gt; throw new InvalidParameterException()
}

def myFunction2: Subroutine = {
  case (firstParam: Int) :: _ =&gt; ...
  case _ =&gt; throw new InvalidParameterException()
}

val routine: Routine = List(
  (myFunction, Seq(firstParam, secondParam)),
  (myFunction2, Seq(firstParam))
)


I realize that this is not close to idiomatic Scala code, and I've been working on implementing a different approach which will partially apply functions one parameter at a time, and then execute the function after the parameters are fully applied. I do not yet have a working version of this approach, but this is as far as I have gotten:

/** A Subroutine simply represents a unit function that takes any number of parameters. */
sealed abstract class Subroutine extends (Any =&gt; Unit)

case class Curried(partiallyApplied: Function[_, Function[_, _]], unapplied: Function[_, _]) extends Subroutine

case class Uncurried(function: Function[_, Unit]) extends Subroutine

/** A Routine represents a collection of functions which may consume a collection of parameters and will always
  * complete an action.
  * Using HList for the parameters, from Shapeless
  */
type Routine = List[(Subroutine, HList)]

/** This function will consume a list of functions executing them in order.
  *
  * @param routine is the list of functions and their parameters to be consumed.
  */
def executeRoutine(routine: Routine): Unit = {
  routine.headOption match {
    case Some((f, x)) =&gt;
      executeSubroutine(f, x)
      executeRoutine(routine.tail)
    case None =&gt; ()
  }
}

private def executeSubroutine(subroutine: Subroutine, params: HList): Any = {
  subroutine match {
    case Curried(partiallyApplied, unapplied) =&gt;
      partiallyApplied(params.head)(executeSubroutine(unapplied, params.tail))
    case Uncurried(function) =&gt; function(params.head)
  }
}


If anyone can help me out that would be greatly appreciated!
Unless I misunderstand your question, I think this is what you want:

type Subroutine[Param] = Param =&gt; Any

type Routine = Seq[(Subroutine[_], Seq[Any])]

def execRoutine(routine: Routine): Unit = routine foreach { case (sub, params) =&gt; execSubroutine(sub, params) }

def execSubroutine[SubParam] (subroutine: Subroutine[SubParam], params: Seq[Any]): Unit = {
    require(params.nonEmpty)

    subroutine(params.head.asInstanceOf[SubParam]) match {
        case sub: Subroutine[_] =&gt; execSubroutine(sub, params.tail)
        case () =&gt; require(params.tail.isEmpty) // Require correct number of params.
        case _ =&gt; throw new IllegalStateException()
    }
}

val add2 = (a: Int) =&gt; (b: Int) =&gt; println(a + b)
val add3 = (a: Int) =&gt; (b: Int) =&gt; (c: Int) =&gt; println(a + b + c)

execRoutine(List(
    (add2, List(3, 4)),
    (add3, List(3, 4, 5))
))


Try it online!

This program prints 7 and 12. Unfortunately, if the parameters are of the wrong type, a runtime exception occurs instead of a compile time one. Attempting to apply the less or more than the required parameters also results in a runtime exception.