使用超类型过滤 HList
Filter a HList using a supertype
import shapeless._
import shapeless.labelled._
import shapeless.tag._
给了一个 HList
赞
case class Foo(a: String, b: Int)
val hlist = LabelledGeneric[Foo].to(Foo("Hello", 42))
还有一个Witness
喜欢
val aW = Witness("a")
我期待这两个表达式
hlist.filter[String with KeyTag[Symbol with Tagged[aW.T], String]]
hlist.filter[KeyTag[Tagged[aW.T], String]]
以产生相同的结果类型。不幸的是,第二个表达式推断为 HNil
.
这是为什么?我如何过滤这样的超类型?
类型 class Filter
是不变的,数据类型 KeyTag
相对于键类型是不变的。所以这不适用于超类型。 implicitly[Filter.Aux[Int :: String :: Boolean :: HNil, AnyVal, Int :: Boolean :: HNil]]
和 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]]
编译。
你应该使用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
如果你想按超类型过滤,那么你应该使用 Collect
并正确定义 Poly
。
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
import shapeless._
import shapeless.labelled._
import shapeless.tag._
给了一个 HList
赞
case class Foo(a: String, b: Int)
val hlist = LabelledGeneric[Foo].to(Foo("Hello", 42))
还有一个Witness
喜欢
val aW = Witness("a")
我期待这两个表达式
hlist.filter[String with KeyTag[Symbol with Tagged[aW.T], String]]
hlist.filter[KeyTag[Tagged[aW.T], String]]
以产生相同的结果类型。不幸的是,第二个表达式推断为 HNil
.
这是为什么?我如何过滤这样的超类型?
类型 class Filter
是不变的,数据类型 KeyTag
相对于键类型是不变的。所以这不适用于超类型。 implicitly[Filter.Aux[Int :: String :: Boolean :: HNil, AnyVal, Int :: Boolean :: HNil]]
和 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]]
编译。
你应该使用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
如果你想按超类型过滤,那么你应该使用 Collect
并正确定义 Poly
。
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