Something like this works for me (modification of this )
object ShapelessStringToTypeConverters { import cats._, implicits._, data.ValidatedNel import mouse._, string._, option._ import shapeless._, labelled._ private type Result[A] = ValidatedNel[ParseFailure, A] case class ParseFailure(error: String) trait Convert[V] { def parse(input: String): Result[V] } object Convert { def to[V](input: String)(implicit C: Convert[V]): Result[V] = C.parse(input) def instance[V](body: String => Result[V]): Convert[V] = new Convert[V] { def parse(input: String): Result[V] = body(input) } implicit def booleans: Convert[Boolean] = Convert.instance( s => s.parseBooleanValidated .leftMap(e => ParseFailure(s"Not a Boolean ${e.getMessage}")) .toValidatedNel) implicit def ints: Convert[Int] = Convert.instance( s => s.parseIntValidated .leftMap(e => ParseFailure(s"Not an Int ${e.getMessage}")) .toValidatedNel) implicit def longs: Convert[Long] = Convert.instance( s => s.parseLongValidated .leftMap(e => ParseFailure(s"Not an Long ${e.getMessage}")) .toValidatedNel) implicit def doubles: Convert[Double] = Convert.instance( s => s.parseDoubleValidated .leftMap(e => ParseFailure(s"Not an Double ${e.getMessage}")) .toValidatedNel) implicit def strings: Convert[String] = Convert.instance(s => s.validNel) } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sealed trait SchemaMap[A] { def readFrom(input: Map[String, String]): ValidatedNel[ParseFailure, A] } object SchemaMap { def of[A](implicit s: SchemaMap[A]): SchemaMap[A] = s private def instance[A](body: Map[String, String] => Result[A]): SchemaMap[A] = new SchemaMap[A] { def readFrom(input: Map[String, String]): Result[A] = body(input) } implicit val noOp: SchemaMap[HNil] = SchemaMap.instance(_ => HNil.validNel) implicit def parsing[K <: Symbol, V: Convert, T <: HList](implicit key: Witness.Aux[K], next: SchemaMap[T]): SchemaMap[FieldType[K, V] :: T] = SchemaMap.instance { input => val fieldName = key.value.name val parsedField = input .get(fieldName) .cata(entry => Convert.to[V](entry), ParseFailure(s"$fieldName is missing").invalidNel) .map(f => field[K](f)) (parsedField, next.readFrom(input)).mapN(_ :: _) } implicit def classes[A, R <: HList](implicit repr: LabelledGeneric.Aux[A, R], schema: SchemaMap[R]): SchemaMap[A] = SchemaMap.instance { input => schema.readFrom(input).map(x => repr.from(x)) } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sealed trait SchemaList[A] { def readFrom(input: List[String]): ValidatedNel[ParseFailure, A] } object SchemaList { def of[A](implicit s: SchemaList[A]): SchemaList[A] = s private def instance[A](body: List[String] => Result[A]): SchemaList[A] = new SchemaList[A] { def readFrom(input: List[String]): Result[A] = body(input) } implicit val noOp: SchemaList[HNil] = SchemaList.instance(_ => HNil.validNel) implicit def parsing[K <: Symbol, V: Convert, T <: HList](implicit key: Witness.Aux[K], next: SchemaList[T]): SchemaList[FieldType[K, V] :: T] = SchemaList.instance { input => val fieldName = key.value.name val parsedField = input .headOption .cata(entry => Convert.to[V](entry), ParseFailure(s"$fieldName is missing").invalidNel) .map(f => field[K](f)) (parsedField, next.readFrom(input.tail)).mapN(_ :: _) } implicit def classes[A, R <: HList](implicit repr: LabelledGeneric.Aux[A, R], schema: SchemaList[R]): SchemaList[A] = SchemaList.instance { input => schema.readFrom(input).map(x => repr.from(x)) } } } /* case class Foo(a: String, b: Int, c: Boolean) def m: Map[String, String] = Map("a" -> "hello", "c" -> "true", "b" -> "100") def e: Map[String, String] = Map("c" -> "true", "b" -> "a100") val result = SchemaMap.of[Foo].readFrom(m) val lst = List("145164983", "0.01862523", "16.11681596", "21:38:57", "bid") case class Trade0(tid: Long, price: Double, amount: Double, time: String, tpe: String) val result2 = SchemaList.of[Trade0].readFrom(lst) */