Search code examples
scalagenericsshapelessscala-2.13

Is there a way to use the type of an object as the argument of a type parameter?


I'm trying to use shapeless to do additions and removals from Hlists. But I can't seem to get it to work.

So I here are my lists:

object ShapelessExample {

    import shapeless._

    def main(args: Array[String]): Unit = {

        case class Container[T <: Singleton](name: T)

        val a = Container("A") :: Container("B") :: Container("C") :: HNil
        val b = Container("B") :: Container("C") :: HNil

        println {
            a.removeAll[b.type] //doesn't work
        }
    }
}

So the removeAll method on Hlist only takes a type parameter, but I can't seem to use b.type. I can manually specify a.removeAll[Container["B"] :: Container["C"] :: HNil], but is there any way to just use b's type?


Solution

  • Shapeless tries to remove precisely type b.type but can't find it among Container["A"] :: Container["B"] :: Container["C"] :: HNil so @user is correct, singleton type b.type is too specific.

    In order to infer an HList type from a val singleton type try to modify the method

    implicit class RemoveAllOps[L <: HList](a: L) {
      def removeAll[L1 <: HList](b: L1)(implicit
        ra: shapeless.ops.hlist.RemoveAll[L, L1]
      ): ra.Out = ra(a)
    }
    
    a.removeAll(b) // (Container(B) :: Container(C) :: HNil,Container(A) :: HNil)
    

    or

    implicit class RemoveAllOps[L <: HList](a: L) {
      def removeAllFrom[O <: Singleton] = new {
        def apply[L1 >: O <: HList]()(implicit
          ra: shapeless.ops.hlist.RemoveAll[L, L1]
        ): ra.Out = ra(a)
      }
    }
    
    a.removeAllFrom[b.type]() //(Container(B) :: Container(C) :: HNil,Container(A) :: HNil)