将 List[String] 解析为 HList [英] Parse List[String] into HList
问题描述
我想写def parse[T <: HList](list: List[String]): Validation[T]
.list
可以是 List("fooid", "barid")
和 T
FooId :: BarId :: HNil
,以及一个实现 String => 的类型类
.我将如何编写将列表解析为 Parse[T]
验证[FooId]T
的 parse
?我不确定如何为 T
的每个元素调用隐式类型类.
I would like to write def parse[T <: HList](list: List[String]): Validation[T]
. list
could be List("fooid", "barid")
, and T
FooId :: BarId :: HNil
, and a typeclass Parse[T]
which implements String => Validation[FooId]
. How would I write said parse
, which parses the list into T
? I'm not sure how to summon the implicit typeclasses for each of the elements of T
.
推荐答案
我们可以修改 shapeless.ops.traversable.FromTraversable
.
We can adapt the code from shapeless.ops.traversable.FromTraversable
.
我不确定您的 Validation
类型是什么,但我将它用作下面 scalaz.ValidationNel[String, A]
的别名(主要是这样我可以使用 string
语法可以轻松地给我一些 Parse
实例).
I'm not sure what your Validation
type is, but I used it as an alias for scalaz.ValidationNel[String, A]
below (mostly so I could use the string
syntax to easily give me some Parse
instances).
import scalaz.{Validation => _, _}, Scalaz._
type Validation[A] = ValidationNel[String, A]
trait Parse[T] {
def apply(s: String): Validation[T]
}
object Parse {
def fromScalazParse[E <: Exception, T](f: String => scalaz.Validation[E, T]) =
new Parse[T] {
def apply(s: String): Validation[T] =
f(s).leftMap(_.getMessage).toValidationNel
}
implicit val booleanParse = fromScalazParse(_.parseBoolean)
implicit val intParse = fromScalazParse(_.parseInt)
implicit val doubleParse = fromScalazParse(_.parseDouble)
}
随着 Parser
类型类的排序,我们现在可以创建一个基于 FromTraversable
的类型类来解析一个 List[String]
并给出我们一个 Validation[A :: B :: HNil]
:
With the Parser
type class sorted, we can now create a type class based on FromTraversable
to parse a List[String]
and give us a Validation[A :: B :: HNil]
:
import shapeless._
import scala.collection.GenTraversable
trait FromTraversableParsed[Out <: HList] extends Serializable {
def apply(l: GenTraversable[String]) : Validation[Out]
}
object FromTraversableParsed {
def apply[Out <: HList](implicit from: FromTraversableParsed[Out]) = from
implicit val hnilFromTraversableParsed =
new FromTraversableParsed[HNil] {
def apply(l: GenTraversable[String]): Validation[HNil] =
if(l.isEmpty) HNil.successNel[String]
else "Traversable is not empty".failureNel[HNil]
}
implicit def hlistFromTraversableParsed[OutH, OutT <: HList](implicit
ftpT: FromTraversableParsed[OutT],
parseH: Parse[OutH]
): FromTraversableParsed[OutH :: OutT] =
new FromTraversableParsed[OutH :: OutT] {
def apply(l : GenTraversable[String]) : Validation[OutH :: OutT] =
if(l.isEmpty) "Empty traversable".failureNel[OutH :: OutT]
else (parseH(l.head) |@| ftpT(l.tail))(_ :: _)
}
}
我们可以添加一些语法来使 FromTraversableParsed
的使用更容易一些:
We can add some syntax to make using FromTraversableParsed
a little bit easier :
implicit class ParseStringListOps(val strings: List[String]) extends AnyVal {
def parse[L <: HList](implicit ftp: FromTraversableParsed[L]): Validation[L] =
ftp(strings)
}
现在我们可以:
List("1", "true", "3.0").parse[Int :: Boolean :: Double :: HNil]
// Validation[Int :: Boolean :: Double :: HNil] = Success(1 :: true :: 3.0 :: HNil)
这篇关于将 List[String] 解析为 HList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!