Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate all the product types in a coproduct using shapeless?

Let's say I have a coproduct (a sealed trait) such as

sealed trait Traity
case object Foo extends Traity
case class Bar() extends Traity
case class Baz() extends Traity

Using shapeless, I can apply polymorphic functions to specific instances but what I'd like to do is to apply a zero-parameter (no-instance) polymorphic function to all the products (i.e. case classes and case objects). I have no idea what the syntax would look like, but something conceptually like:

object mypoly extends Poly1 {
  implicit def traity[T <: Traity] = when[T]( getClass[T].toString )
}

iterate[Traity](mypoly) // gives List("Foo", "Bar", "Baz")

would suit my purposes.

like image 288
fommil Avatar asked Apr 16 '15 13:04

fommil


1 Answers

For the example use case in your question, this is actually very straightforward:

import shapeless._

class NameHelper[A] {
  def apply[C <: Coproduct, K <: HList]()(implicit
    gen: LabelledGeneric.Aux[A, C],
    keys: ops.union.Keys.Aux[C, K],
    toSet: ops.hlist.ToTraversable.Aux[K, Set, Symbol]
  ): Set[String] = toSet(keys()).map(_.name)
}

def names[A] = new NameHelper[A]

And then:

scala> names[Traity]()
res0: Set[String] = Set(Bar, Baz, Foo)

(I'm using a Set since the order you're getting is just alphabetical—it's not currently possible to enumerate the constructors in declaration order, although I'd personally prefer that.)

If you'd like a more generic answer, an adaptation of the code in the question I linked above shouldn't be too bad—I'd be happy to add it here later.

like image 195
Travis Brown Avatar answered Nov 09 '22 22:11

Travis Brown