HList filtered by foldRight is not providing insta

2020-07-22 17:22发布

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?

1条回答
疯言疯语
2楼-- · 2020-07-22 18:03

Your eventual fix is almost, but not quite, right. Rather than asInstanceOf you should use a type ascription,

view.foldRight(HNil: HNil)(collectVisRF)

Your question about why there is no definition of an hnil value typed as HNil rather than as HNil.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 where None.type and Nil.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 of HNil (the value) rather than HNil.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 :-)

查看更多
登录 后发表回答