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.

+3


source to share


2 answers


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

.

+1


source


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 = ???
}

      

-2


source







All Articles