score:2

what you're trying to do is very easy to achieve using a variant of a pattern called magnet. first let's define some types:

sealed trait in

case class in1() extends in
case class in2() extends in

sealed trait out //mystery2

case class out1() extends out
case class out2() extends out

sealed trait name //mystery1

case class name1() extends name
case class name2() extends name

sealed trait row //mystery3

case class row1() extends row
case class row2() extends row

then we can prepare our magnet typeclass:

sealed trait magnet[n <: name, i <: int, o <: out] {
   type result <: row

   def apply(name: n, in: i, out: o): result
}

inside of companion object of magnet you can add entries to "lookup" as implicit values:

import scala.languagefeature.implicitconversions //you can also enable implicit conversions in build.sbt

object magnet {

  implicit val function1 = new magnet[name1, in1, out2] {
     override type result = row1

     override def apply(name: name1, in: in1, out:out2): row1 = ???
  }

  implicit val function2 = new magnet[name2, in2, out1] {
     override type result = row2

     override def apply(name: name2, in: in2, out: out1): row2 = ???
  }

}

finally, we can prepare invoketherightfunction function, which will require implicitly magnet:

def invoketherightfunction[n <: name, i <: int, o <: out](name: n, in: i, out: o)(implicit magnet: magnet[n,i,o]): magnet.result = magnet(name, in, out)

let's test it out:

val r1: row1 = invoketherightfunction(name1(), in1(), out2())

val r2: row2 = invoketherightfunction(name2(), in2(), out1())

Related Query

More Query from same tag