I'm trying to use shapeless's hlist to construct introspectable URL templates, but I'm having trouble with traversing my HList. The following doesn't compile:
import shapeless.{::, HList, HNil}
import shapeless.LUBConstraint._
import shapeless.ops.hlist.ToTraversable._
import scala.util.Try
import shapeless.ops.hlist._
object Path {
def /(s: String) = Path(PathLiteral(s) :: HNil)
def param[T](name: String) = PathParameter(name)
}
sealed trait PathSegment[+T]
case class PathLiteral(value: String) extends PathSegment[String]
case class PathParameter[+T](name: String) extends PathSegment[T]
case class Path[L <: HList : <<:[PathSegment[_]]#λ](segments: L)
(implicit ev: ToList[L, PathSegment[_]])
{
def /(literal: String) = Path(PathLiteral(literal) :: segments)
def /[T](param: PathParameter[T]) = Path(param :: segments)
override def toString: String = s"Path(${segments.toList.reverse})"
}
object Test extends App {
import Path.param
val myPath = Path / "v1" / "pets" / param[String]("name") / "pictures"
println(myPath)
}
It seems to me like the ToTraversable._
import covers the HNil case and the case of having the tail of an HList and a new head with the same Least Upper Bound. Obviously I'm either missing an import or misunderstanding everything.
I'm not sure if caching the evidence in the class as an implicit parameter is kosher; I'm doing it because
- I don't want hlist details to leak into the external API
- I need it for a nice toString