Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Case Classes with Same Shape?

Given two case classes:

case class Foo(x: Int)
case class Bar(x: Int)

Using shapeless, how can I determine if Foo and Bar have the same "shape", i.e. Int :: HNil is HList?

like image 906
Kevin Meredith Avatar asked Jan 03 '23 13:01

Kevin Meredith


2 Answers

A, B have same shape if there exists a shape S such that S is the generic representation of both A and B. This translates directly into the following function:

trait SameShape[A, B]

object SameShape {
  implicit def instance[A, B, S]
    (implicit a: Generic.Aux[A, S], b: Generic.Aux[B, S]): SameShape[A, B] =
      new SameShape[A, B] {}
}
like image 113
OlivierBlanvillain Avatar answered Jan 06 '23 03:01

OlivierBlanvillain


For specific case classes you can just do:

  case class Foo(x: Int)
  case class Bar(x: Int)
  case class Baz(x: String)

  implicitly[Generic.Aux[Foo, Int :: HNil]]
  implicitly[Generic.Aux[Bar, Int :: HNil]]
  implicitly[Generic.Aux[Baz, String :: HNil]]

More general approach:

If you prefer to work with values you can create function:

  def test[A, B, L <: HList](a: A, b: B)(implicit
                                         gen1: Generic.Aux[A, L],
                                         gen2: Generic.Aux[B, L]): Int = 42

  val foo = Foo(1)
  val bar = Bar(2)
  val baz = Baz("a")

  test(foo, bar)  // compiles
//  test(foo, baz)  // doesn't compile

If you prefer to work with types you can create type class:

  trait SameShape[A, B]

  object SameShape {
    implicit def mkSameShape[A, B, L <: HList](implicit
                                               gen1: Generic.Aux[A, L],
                                               gen2: Generic.Aux[B, L]
                                               ): SameShape[A, B] =
      new SameShape[A, B] {}
  }

  implicitly[SameShape[Foo, Bar]]  // compiles
//  implicitly[SameShape[Foo, Baz]] // doesn't  compile
like image 25
Dmytro Mitin Avatar answered Jan 06 '23 03:01

Dmytro Mitin