Search code examples
scalafunctional-programmingshapelesscoproduct

Coproducts in shapeless does not compile


I'm experimenting with shapeless and now trying to understand Generic for Coproducts. Here is what I tried:

object ShapelessExperiments {
    final case class Test1()
    final case class Test2()
    final case class Test3()

    type Test = Test1 :+: Test2 :+: Test3 :+: CNil

    val t1: Test = Inr(Inl(Test2()))  //fine
    val t2: Test = Generic[Test].to(Test2())  //compile error
}

I expected val t2 to be exactly the same as val t1, but unfortunately it does not even compile:

Error:(13, 25) could not find implicit value for parameter gen: shapeless.Generic[com.test.ShapelessExperiments.Test]
  val t2: Test = Generic[Test].to(Test2())

Error:(13, 25) not enough arguments for method apply: (implicit gen: shapeless.Generic[com.test.ShapelessExperiments.Test])shapeless.Generic.Aux[com.test.ShapelessExperiments.Test,gen.Repr] in object Generic.
Unspecified value parameter gen.
  val t2: Test = Generic[Test].to(Test2())

This error does is not really clear and helpful to me. Can you please explain what went wrong in the final case?


Solution

  • I think you're looking for Inject:

    import shapeless._
    import shapeless.ops.coproduct.Inject // for converter object
    import shapeless.syntax.inject._ // for nice syntax
    
    object ShapelessExperiments extends App {
        final case class Test1()
        final case class Test2()
        final case class Test3()
    
        type Test = Test1 :+: Test2 :+: Test3 :+: CNil
    
        val t1: Test = Inr(Inl(Test2()))  //fine
        val t2: Test = Inject[Test, Test2].apply(Test2())
        val t3: Test = Test2().inject[Test]
        println(t1 == t2) // true
        println(t1 == t3) // true 
    }
    

    Generic[A] purpose is different: it says that A is isomorphic (can be transformed to and from, without any data loss) to some type B, where B is usually an HList (if A is a case class) or a Coproduct (if A is a sealed trait).

    These instances are not available when A is an HList or a Coproduct itself (source).