The following is a simple recursive solution to your problem. However, note that passing the possible values as a Set
might turn out to be problematic because this way there is no order on the possible values and hence all (and not only one in particular) corresponding parameters will iterate over all values with suitable parameter types. Now this should do what you asked:
case class ParamType(name: String) {
def matchesType(that: ParamType): Boolean =
this.name == that.name
}
sealed abstract class Param(val paramType: ParamType)
case class VarParam(parameter: String, override val paramType: ParamType) extends Param(paramType)
case class ValueArg(name: String, override val paramType: ParamType) extends Param(paramType)
case class Action(name: String, params: List[Param]) {
lazy val varParams: List[Param] =
params collect {
case pt: VarParam => pt
}
def possibleActions(possibleValues: Set[ValueArg]): Set[Action] = {
val pvs = possibleValues groupBy (_.paramType)
def aux(acc: List[Param], rem: List[Param]): Set[Action] = rem match {
case Nil => Set(Action(name, acc.reverse))
case x :: xs => for {
pv <- pvs(x.paramType) if pvs.contains(x.paramType)
rest <- aux(pv :: acc, xs)
} yield rest
}
aux(Nil, varParams)
}
}
val possibleValues = Set(
ValueArg("a1", ParamType("Atype")),
ValueArg("a2", ParamType("Atype")),
ValueArg("a3", ParamType("Atype")),
ValueArg("b1", ParamType("Btype")),
ValueArg("b2", ParamType("Btype")),
ValueArg("b3", ParamType("Btype")),
ValueArg("c1", ParamType("Ctype")),
ValueArg("c2", ParamType("Ctype")),
ValueArg("c3", ParamType("Ctype")))
val action1 = Action("action1",
List(VarParam("A", ParamType("Atype")),
VarParam("B", ParamType("Btype")),
VarParam("C", ParamType("Ctype"))))
val possibleActions = action1.possibleActions(possibleValues)
assert(possibleActions.size == 3 * 3 * 3)