I'm using libraryDependencies += "com.chuusai" %% "shapeless" % "2.2.4"
Currently i have model HList types like
sealed trait Section
case class Header(...) extends Section
case class Customer(...) extends Section
case class Supplier(...) extends Section
case class Tech(...) extends Section
type ContractView = Header :: (Customer :: Supplier :: HNil) :: Tech :: HNil
In my user code, i'd like to filter technical sections that are not supposed to view using foldRight
as proposed in this answer:
trait collectAllRF extends Poly2 {
implicit def atAny[L <: HList, X] = at[X, L](_ :: _)
}
object collectVisRF extends collectAllRF {
implicit def atInvis[L <: HList, S <: Section : InvisibleSection] = at[S, L]((_, l) => l)
}
For example there are defined:
trait InvisibleSection[S <: Section]
implicit object _techisInvisible extends InvisibleSection[Tech]
Fold is working correctly, but suddenly i could not use following filter
or map
on this object, so for example this code:
val filtered = view.foldRight(HNil)(collectVisRF)
view.filter[Header]
produces compile error:
error: could not find implicit value for parameter partition: shapeless.ops.hlist.Partition[shapeless.::[Header,shapeless.::[shapeless.::[Customer,shapeless.::[Supplier,shapeless.HNil]],shapeless.HNil.type]],Header]
while this
view.filter[Header]
and this
val h = view.select[Header]
val l = view.select[Customer::Supplier::HNil]
val c = l.select[Customer]
val s = l.select[Supplier]
val manual = h :: (c :: s :: HNil) :: HNil
manual.filter[Header]
compiles ok
Lately i've found little HNil.type
at end of foldRight
's result type and changed my filter definition to
view.foldRight(HNil.asInstanceOf[HNil])(collectVisRF)
And all worked properly
Is this an expected behaviour, and if yes why there is no some
val hNil: HNil = HNil
In the library?
Your eventual fix is almost, but not quite, right. Rather than
asInstanceOf
you should use a type ascription,Your question about why there is no definition of an hnil value typed as
HNil
rather than asHNil.type
is a good one. shapeless is different from typical Scala libraries in that it makes heavy use of singleton types,HNil.type
included, so the current situation isn't as obviously wrong as the corresponding situation in the Scala standard library whereNone.type
andNil.type
are almost never desired.Nevertheless the situation you describe in your question comes up more often than I would like, so it's clearly a real problem. I think it would be too confusing to have two hnil values, one with a more precise type than the other, so the question boils down to: how much existing stuff would break if
HNil
(the type) was inferred as the type ofHNil
(the value) rather thanHNil.type
as it is now.Feel free to open a ticket in the shapeless issue tracker on Github to investigate this, and if you'd like to give it a try, please do :-)