问题
Here is a simple example in shapeless 2.3.3:
val book =
("author" ->> "Benjamin Pierce") ::
("title" ->> "Types and Programming Languages") ::
("id" ->> 262162091) ::
("price" ->> 44.11) ::
HNil
val v1 = book.values
assert(v1.head == "Benjamin Pierce") // works fine
// summoning Values[_] type class explicitly, the HList & TypeTag are optional
case class HasValues[T <: HList: TypeTag](v: T) {
def vs(implicit v: Values[T]): Values[T] = v
}
val _vs = HasValues(book).vs
val v2 = book.values(_vs)
assert(v2.head == "Benjamin Pierce") // compilation error!
The last line, despite v2 being syntactically identical to v1, gave the following error:
: could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[com.tribbloids.spike.shapeless_spike.RecordProblem._vs.Out]
one error found
Further investigation indicates that the type hierarchy of symbol v1 looks like this:
-+ String :: String :: Int :: Double :: shapeless.HNil
: `-+ [ 2 ARGS ] :
: !-+ String .................................................................................................................. [0]
: : !-+ CharSequence
: : : !-+ Object .................................................................................................................. [1]
: : : !-- Any ..................................................................................................................... [2]
: : !-- Comparable[String]
: : : `-+ [ 1 ARG ] :
: : : !-- String .................................................................................................................. [0]
: : !-- java.io.Serializable .................................................................................................... [3]
: !-+ String :: Int :: Double :: shapeless.HNil
: : `-+ [ 2 ARGS ] :
: : !-- String .................................................................................................................. [0]
: : !-+ Int :: Double :: shapeless.HNil
: : : `-+ [ 2 ARGS ] :
: : : !-+ Int
: : : : !-+ AnyVal .................................................................................................................. [4]
: : : : !-- Any ..................................................................................................................... [2]
: : : !-+ Double :: shapeless.HNil
: : : : `-+ [ 2 ARGS ] :
: : : : !-+ Double
: : : : : !-- AnyVal .................................................................................................................. [4]
: : : : !-+ shapeless.HNil
: : : : !-+ shapeless.HList ......................................................................................................... [5]
: : : : !-+ Serializable
: : : : : !-- java.io.Serializable .................................................................................................... [3]
: : : : !-+ Product
: : : : : !-- Equals
: : : : !-- Object .................................................................................................................. [1]
: : : !-- shapeless.HList ......................................................................................................... [5]
: : !-- shapeless.HList ......................................................................................................... [5]
: !-- shapeless.HList ......................................................................................................... [5]
!-- shapeless.HList ......................................................................................................... [5]
But the type hierarchy of v2 omitted most information:
-+ com.tribbloids.spike.shapeless_spike.RecordProblem._vs.Out
!-+ shapeless.HList
!-+ Serializable
: !-+ java.io.Serializable
: !-- Any
!-+ Product
: !-- Equals
!-- Object
What's the cause of this and how do I summon the type class of Value[_] properly?
回答1:
You lost type refinement. Replace
case class HasValues[T <: HList: TypeTag](v: T) {
def vs(implicit v: Values[T]): Values[T] = v
}
with
case class HasValues[T <: HList: TypeTag](v: T) {
def vs(implicit v: Values[T]): Values.Aux[T, v.Out] = v
}
Then both
val v2 = book.values
assert(v2.head == "Benjamin Pierce")
and
val v2 = book.values(_vs)
assert(v2.head == "Benjamin Pierce")
compile.
In scala, what is the easiest way to chain functions defined with a type class and of which output type depends on it?
来源:https://stackoverflow.com/questions/65618971/in-scala-2-13-why-is-it-sometimes-impossible-to-summon-type-class-explicitly