将 Sized[Something[String], _] 集合转换为 HList

Convert Sized[Something[String], _] collection to HList

我是 shapeless 的新手,正在尝试边做边学。我想制作一个非常小的库,它可以将 String 的集合(第一步是 Sized 集合)转换为不同类型的 HList。

基本上我想要达到的目标:

import shapeless._
import nat._
import BigQueryParser._

val s: Sized[IndexedSeq[String], nat._3] = Sized("Testing", "2.0", "1")

BigQueryParser[Sized[IndexedSeq[String], nat._3], String :: BigDecimal :: BigInt :: HNil].parse(s)

我的非工作实现在这里https://gist.github.com/taojang/f6a9352dbc618039e3a3

我是在https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/csv.scala

之后实现的

我的代码无法编译,编译器抱怨以下错误:

[error] /somepath/some-file.scala: could not find implicit value for parameter st: exmaple.BigQueryParser[shapeless.Sized[IndexedSeq[String],shapeless.nat._3],shapeless.::[String,shapeless.::[BigDecimal,shapeless.::[BigInt,shapeless.HNil]]]]
[error]   BigQueryParser[Sized[IndexedSeq[String], nat._3], String :: BigDecimal :: BigInt :: HNil].parse(s)

我发现调试此类问题的最佳方法是尝试手动构建您的实例。例如,这很好:

scala> BigQueryParser[Sized[IndexedSeq[String], _0], HNil]
res0: BigQueryParser[shapeless.Sized[IndexedSeq[String],shapeless.nat._0],shapeless.HNil] = BigQueryParser$$anon@2f4cd46d

但这会中断:

scala> deriveHCons[IndexedSeq[String], _0, String, HNil]
<console>:31: error: could not find implicit value for parameter conv: BigQueryParser[scala.collection.generic.IsTraversableLike[IndexedSeq[String]]#A,String]
       deriveHCons[IndexedSeq[String], _0, String, HNil]
                  ^

这表明 IsTraversableLike[Repr]#A 类型的投影出了问题。在这种情况下,我要做的第一件事就是将其设为类型参数(在本例中为 ReprA),然后使用细化类型约束 IsTraversableLike[Repr] 实例:

implicit def deriveHCons[Repr, ReprA, L <: Nat, V, T <: HList](implicit
  itl: IsTraversableLike[Repr] { type A = ReprA },
  ev: AdditiveCollection[Repr],
  ts: BigQueryParser[Sized[Repr, L], T],
  conv: BigQueryParser[ReprA, V]
): BigQueryParser[Sized[Repr, Succ[L]], V :: T] =
  new BigQueryParser[Sized[Repr, Succ[L]], V :: T] {
    def parse(s: Sized[Repr, Succ[L]]): Try[V :: T] =
      for {
        h <- conv.parse(s.head)
        t <- ts.parse(s.tail)
      } yield h :: t
  }

这很好用:

scala> println(
     |   BigQueryParser[
     |     Sized[IndexedSeq[String], nat._3],
     |     String :: BigDecimal :: BigInt :: HNil
     |   ].parse(s)
     | )
Success(Testing :: 2.0 :: 1 :: HNil)

您可能还可以进行其他简化(例如,直接使用 _0 而不是 L <: _0 类型参数),但此修复至少应该让事情顺利进行。