Search code examples
scalashapeless

How can I match case with shapeless variable?


How can I match case with shapeless variable ?

Let's say I have variable of following type shapeless.::[String,shapeless.::[String,shapeless.HNil]]

Currently I have to do this

authHeaders.hrequire(shape_value => {
    val (client_id, client_secret) = value.tupled
    isAuthorized(client_id, client_secret)
  }
  )

Can I somehow unwind String :: String :: HNil to String pair so that I don't have to do it in separate statement ?


Solution

  • There is method unapply in object shapeless.:::

    def unapply[H, T <: HList](x: H :: T): Option[(H, T)]
    

    So you could just match on HList like this:

    scala> val ::(a, ::(b, HNil)) = "1" :: "x" :: HNil
    a: String = 1
    b: String = x
    

    Or with alternative syntax for unapply method with Tuple2 result: a :: b instead of ::(a, b):

    scala> val a :: b :: HNil = "1" :: "x" :: HNil
    a: String = 1
    b: String = x
    
    scala> "1" :: "x" :: HNil match {
         |   case a :: b :: HNil => s"$a :: $b :: HNil"
         | }
    res0: String = 1 :: x :: HNil
    

    In your case:

    authHeaders.hrequire{
      case client_id :: client_secret :: HNil => isAuthorized(client_id, client_secret)
    }
    

    Alternative

    You could use tupled method to convert function of N arguments to function of single TupleN argument.

    For function:

    val isAuthorized: (String, String) => Boolean = ???
    authHeaders.hrequire{ isAuthorized tupled _.tupled }
    

    For method:

    def isAuthorized(s1: String, s2: String): Boolean = ???
    authHeaders.hrequire{ (isAuthorized _) tupled _.tupled }