Search code examples
scalashapelesshlist

HList as parameter of method with simplified type signature


Suppose I have container-marker

case class TypedString[T](value: String)

where value represents some id for particular type T.

I have two classes

case class User(id: String)
case class Event(id: String)

And I have a function which does some stuff:

def func[L <: HList](l: L)(...) {...}

So I can use it like

func[TypedString[User] :: TypedString[Event] :: HNil](
    TypedString[User]("user id") :: TypedString[Event]("event id") :: HNil
)

(it's important for me to keep type signature explicitly)

The question is: how to change or extends func to have shorter type signature (keeping only marker types) like:

func[User :: Event :: HNil](
    TypedString[User]("user id") :: TypedString[Event]("event id") :: HNil
)

Solution

  • The shapeless.ops.hlist.Mapped type class gives you the relation of one HList L and another HList where the elements of L are wrapped in a type constructor.

    Because you have now two types, the type L you want to specify and another type (the elements of L wrapped in TypedString), we need to use the same trick we used in your previous question (then because we didn't want to supply all the arguments at once, now because we only want to specify the first type).

    import shapeless._
    import ops.hlist.Mapped
    
    def func[L <: HList] = new PartFunc[L]
    
    class PartFunc[L <: HList] {
      def apply[M <: HList](m: M)(implicit mapped: Mapped.Aux[L, TypedString, M]): M = m
    }
    

    Now you can use func as you wanted :

    func[User :: Event :: HNil](
        TypedString[User]("user id") :: TypedString[Event]("event id") :: HNil
    )
    // TypedString[User] :: TypedString[Event] :: HNil =
    //     TypedString(user id) :: TypedString(event id) :: HNil