scalashapelesshlist

Function that retrieves element from HList (while preserving its type)


I have this type which will be generated via shapeless:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

Basically I have a bunch of case objects extending a trait so I managed to create a method which gives me instances of all case objects as an HList

Then using import shapeless.ops.hlist.Last and init I wrote a method to retrieve one of the nodes in the HList if the value is equal to the string "student":

def getLast(hl:hlistt) = {
  val last0=Last[hlistt]
  val la=last0(hl)

  if (la.value == "student") la
  else init(hl)
}

The issue is that if I call this method I will not get the correct node type from the HList.

getLast(STUDENT :: AUTO_LOANS :: HNil)

The method works and returns the node but the type is off:

Product with Serializable = STUDENT :: HNil

Do I need some Witness/Aux implicits to return the correct type?


Solution

  • la is of type AUTO_LOANS.type, init(hl) is of type STUDENT.type :: HNil, so

    if (la.value == "student") la
    else init(hl)
    

    is of type Any (or Product with Serializable).

    If you would like to return values of different types from different branches you need a Poly.

    import shapeless.{Poly1, Witness}
    
    object myPoly extends Poly1 {
      implicit def studentCase: Case.Aux[Witness.`"student"`.T, STUDENT.type] = 
        at(_ => STUDENT)
      implicit def autoLoansCase: Case.Aux[Witness.`"auto-loans"`.T, AUTO_LOANS.type] = 
        at(_ => AUTO_LOANS)
    }
    
    import shapeless.syntax.singleton._
    println(
      myPoly("student".narrow)
    ) // STUDENT
    
    println(
      myPoly("auto-loans".narrow)
    ) // AUTO_LOANS
    
    // println(
    //   myPoly("abc".narrow)
    // )  // doesn't compile
    

    This approach works if the string is known at compile time.