Search code examples
scalashapelesshlistmap-function

Mapping tuples in shapeless HList


You do

  import shapeless._ ; import poly._

  object fun extends (List ~>> (List, Int)) {
    override def apply[T](list: List[T]): (List, Int) = list -> list.size
  }

  println((List(1,2,3) :: List("a", "b", "c") :: HNil).map(fun))

to map every sublist into a couple. However, what if HList elements are more complex, like tutples, for instance? The natural attempt

  object fun extends ((String -> List) ~>> (List, Int)) {
    override def apply[T](list: (String -> List[T])): (List, Int) = list -> list.size

is rejected by the compiler. What do you do? Where can you learn that?


Solution

  • import shapeless._
    import poly._
    
    object fun2 extends Poly1 {
      implicit def caseTuple[T] =
        at[(String, List[T])](x => (x._2.tail, x._1.toInt))
    }
    

    Then:

    println((("56", List(1,2,3)) :: ("78", List(4,2,3)) :: HNil).map(fun))
    

    Or if you want to do it with original ~> it's yet still possible, but looks ugly to my taste:

    object fun3 extends (({type L[T] = (String, List[T])})#L ~> ({type L[T] = (List[T], Int)})#L) {
      override def apply[T](f: (String, List[T])): (List[T], Int) = f match {
        case (str, list) => (list.tail, str.toInt)
      }
    }
    
    println((("56", List(1,2,3)) :: ("78", List(4,2,3)) :: HNil).map(fun3))
    

    P.S. Also please note that your code example does not compile. You miss [T] in the first part, you need to use ~> and String -> List is a wrong type in scala in the last part. List is a type constructor, not type and you can't use it this way