Variable number of arguments for an abstract function
I have the following code:
trait TypeLike
trait ArgLike
trait Predicate{
def name:String
}
case class Arg(name:String)
case class Predicate1[I1<:Arg,O<:TypeLike](name:String, arg1:I1, output:O, func: I1=> O) extends Predicate
case class Predicate2[I1<:Arg,I2<:Arg,O<:TypeLike](name:String, arg1:I1,arg2:I2, output:O, func: (I1,I2)=> O)
extends Predicate
How can I add "func" to the Predicate property. I don't know how to define an abstract function with variable input numbers.
source to share
Unfortunately, you have to use HLists for this. Here's an example with Shapeless HLists:
import shapeless._
trait Predicate[Args <: HList, O <: TypeLike] {
implicit val lubWitness: LUBConstraint[Args, Arg]
def name: String
def func: Args => O
}
case class Predicate1[I1 <: Arg, O <: TypeLike](
name: String,
arg1: I1,
output: O,
func: I1 :: HNil => O
) extends Predicate[I1 :: HNil, O] {
implicit val lubWitness = implicitly[LUBConstraint[I1 :: HNil, Arg]]
}
case class Predicate2[I1 <: Arg, I2 <: Arg, O <: TypeLike](
name: String,
arg1: I1,
arg2: I2,
output: O,
func: I1 :: I2 :: HNil => O
) extends Predicate[I1 :: I2 :: HNil, O] {
implicit val lubWitness = implicitly[LUBConstraint[I1 :: I2 :: HNil, Arg]]
}
// Example instantiation
val p1 = Predicate1("Example", Arg("test"), new TypeLike {},
(args: Arg :: HNil) => { println(args(0)); ??? })
Explanation
And what's going on here? HList is basically a stereoid tuple. Let's look at the example we have:
trait Predicate[Args <: HList, O <: TypeLike] {
Args <: HList
means Args
- list of types. O <: TypeLike
is a normal type parameter with a binding.
implicit val lubWitness: LUBConstraint[Args, Arg]
This suggests that we need proof that every type in the HList Args
is a subtype Arg
(I assumed this was a requriement.
def func: Args => O
A function that takes an HList "shape" Args
and returns a O
. (You can also write this as a method if you like.
case class Predicate1 /*snip*/ extends Preciate[I1 :: HNil, O]
Predicate1
is one Predicate
whose argument list contains one type element I1
.
implicit val lubWitness = implicitly[LUBConstraint[I1 :: HNil, Arg]]
Get and define the witness what I1
the subtype is Arg
(in this case, due to the type constraint in the declaration Predicate1
.
source to share
Tuples as type parameters could mimic something similar to your question. This approach has 2 limitations. You have to use additional parsers to call func, and the tuple is limited to 22 items.
trait TypeLike
trait ArgLike
trait Predicate[X, O] {
def name:String
def func(f: X): O
}
case class Arg(name:String)
case class Predicate1[I1<:Arg,O<:TypeLike, X <: Tuple1[I1]](name:String, arg1:I1, output:O) extends Predicate[X, O] {
override def func(f: X): O = ???
}
case class Predicate2[I1<:Arg,I2<:Arg,O<:TypeLike, X <: Tuple2[I1, I2]](name:String, arg1:I1,arg2:I2, output:O)
extends Predicate[X, O] {
override def func(f: X): O = ???
}
source to share