I'm new to shapeless and trying to learning it by doing. I want to make a very small library which can convert a collection (in first step a Sized collection) of String, to HList of different types.
basically what I want to achieve:
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)
My non-working implementation is here https://gist.github.com/taojang/f6a9352dbc618039e3a3
I implemented it after https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/csv.scala
My code does not compile, compiler complains about following errors:
[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)
答案 0 :(得分:6)
I find that the best way to debug these kinds of issues is to try to build your instances by hand. For example, this is fine:
scala> BigQueryParser[Sized[IndexedSeq[String], _0], HNil]
res0: BigQueryParser[shapeless.Sized[IndexedSeq[String],shapeless.nat._0],shapeless.HNil] = BigQueryParser$$anon$6@2f4cd46d
But this breaks:
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]
^
Which suggests that something is going wrong with the IsTraversableLike[Repr]#A
type projection. The first thing I'd do in a situation like that is make it a type parameter (ReprA
in this case) and then constrain the IsTraversableLike[Repr]
instance with a refinement type:
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
}
And that works just fine:
scala> println(
| BigQueryParser[
| Sized[IndexedSeq[String], nat._3],
| String :: BigDecimal :: BigInt :: HNil
| ].parse(s)
| )
Success(Testing :: 2.0 :: 1 :: HNil)
There may be other simplifications you could make (e.g. using _0
directly instead of a L <: _0
type parameter), but this fix should at least get things rolling.