简体   繁体   English

使用超类型过滤 HList

[英]Filter a HList using a supertype

import shapeless._
import shapeless.labelled._
import shapeless.tag._

Given a HList like给定一个HList

case class Foo(a: String, b: Int)

val hlist = LabelledGeneric[Foo].to(Foo("Hello", 42))

and a Witness like和像这样的Witness

val aW = Witness("a")

I expect the two expressions我期待这两种表达方式

hlist.filter[String with KeyTag[Symbol with Tagged[aW.T], String]]
hlist.filter[KeyTag[Tagged[aW.T], String]]

to yield the same result type.产生相同的结果类型。 Unfortunately, the second expression infers to HNil .不幸的是,第二个表达式推断为HNil

Why is that?这是为什么? How can I filter on supertypes like this?我如何过滤这样的超类型?

Type class Filter is invariant, data type KeyTag is invariant with respect to key type.类型 class Filter是不变的,数据类型KeyTag相对于键类型是不变的。 So this can't work with a supertype.所以这不适用于超类型。 implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyVal, Int:: Boolean:: HNil]] and implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyRef, String:: HNil]] don't compile, implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyVal, HNil]] and implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyRef, HNil]] compile instead. implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyVal, Int:: Boolean:: HNil]] and implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyRef, String:: HNil]]不编译, implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyVal, HNil]]implicitly[Filter.Aux[Int:: String:: Boolean:: HNil, AnyRef, HNil]]编译。

You should use Filter as follows您应该按如下方式使用Filter

implicitly[Filter.Aux[Record.`'a -> String, 'b -> Int`.T, FieldType[Symbol @@ "a", String], Record.`'a -> String`.T]]
implicitly[Filter.Aux[Record.`'a -> String, 'b -> Int`.T, FieldType[Symbol @@ aW.T, String], Record.`'a -> String`.T]]

hlist.filter[FieldType[Witness.`'a`.T, String]] // Hello :: HNil
hlist.filter[FieldType[Symbol @@ Witness.`"a"`.T, String]] // Hello :: HNil
hlist.filter[FieldType[Symbol @@ "a", String]] // Hello :: HNil
hlist.filter[FieldType[Symbol @@ aW.T, String]] // Hello :: HNil
hlist.filter[FieldType[Symbol with Tagged[aW.T], String]] // Hello :: HNil
hlist.filter[String with KeyTag[Symbol with Tagged[aW.T], String]] // Hello :: HNil

If you want to filter by a supertype then you should use Collect with properly defined Poly .如果您想按超类型过滤,那么您应该使用带有正确定义的PolyCollect

trait SuperPoly[Upper] extends Poly1
object SuperPoly {
  implicit def cse[P <: SuperPoly[Upper], Upper, A](implicit
    unpack: Unpack1[P, SuperPoly, Upper],
    ev: A <:< Upper
  ): poly.Case1.Aux[P, A, A] = poly.Case1(identity)
}

implicitly[Collect.Aux[Int :: String :: Boolean :: HNil, SuperPoly[AnyVal], Int :: Boolean :: HNil]]
implicitly[Collect.Aux[Int :: String :: Boolean :: HNil, SuperPoly[AnyRef], String :: HNil]]

implicitly[Collect.Aux[Record.`'a -> String, 'b -> Int`.T, SuperPoly[KeyTag[_ <: Tagged[aW.T], String]], Record.`'a -> String`.T]]
val aPoly = new SuperPoly[KeyTag[_ <: Tagged[aW.T], String]] {}
implicitly[Collect.Aux[Record.`'a -> String, 'b -> Int`.T, aPoly.type, Record.`'a -> String`.T]]

hlist.collect(aPoly) // Hello :: HNil

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM