Search code examples
scalashapeless

How to append an element to HList


I'm experimenting with the following class

import shapeless._
import syntax.std.tuple._

class TestedClass[HL](nodes: HL) {

    def addElement[T, OUT](clause: HL => T) = {
        new TestedClass[OUT](nodes :+ clause(nodes))
    }
}

Obviously this fragment doesn't compile. I don't know how to bind the new tuple nodes :+ clause(nodes) type to OUT. What I would like to achieve is the following:

scala> val step1 = new TestedClass[(Int)](1)
res1: TestedClass[(Int)]

scala> val step2 = step1.addElement(nodes => 2.0)
res1: TestedClass[(Int, Double)]

Is it possible with Scala?


Solution

  • Yes, it's possible, although not quite so nicely, since Scala doesn't provide syntax for Tuple1. But the following will work:

    import shapeless._, ops.tuple.Prepend
    
    class TestedClass[HL](nodes: HL) {
      def addElement[T, OUT](clause: HL => T)
        (implicit prepend: Prepend.Aux[HL, Tuple1[T], OUT]) = {
          new TestedClass[OUT](prepend(nodes, Tuple1(clause(nodes))))
        }
    }
    

    And then:

    scala> val step1 = new TestedClass[Tuple1[Int]](Tuple1(1))
    step1: TestedClass[(Int,)] = TestedClass@4fb78b02
    
    scala> val step2 = step1.addElement(nodes => 2.0)
    step2: TestedClass[(Int, Double)] = TestedClass@20406333
    

    The basic trick whenever you want to use an operation from Shapeless is to find the type class you need and require the appropriate instance as an implicit parameter. In this case the Prepend for tuples is what we want.