无形。如何按键过滤LabelledGeneric记录?
Shapeless. How filter LabelledGeneric record by keys?
我有下一段代码要用于类型 class 实例创建:
def productsLogShow[HK <: HList, T, H <: HList, K](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], keys: Keys.Aux[H, K]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
// ...
//filter somehow record and get a record without
// keys which are in 'hideFieldsWithKeys'
// ...
}
}
那么,如何过滤记录以及如何为 hideFieldsWithKeys
参数使用正确的类型?
更新:
根据 Dmitro 的回答应该可以工作的完整代码片段
object Main extends App {
trait LogShow[T] {
def show(value: T): String
}
object LogShow {
def apply[T: LogShow]: LogShow[T] = implicitly[LogShow[T]]
def create[T](f: T => String): LogShow[T] = new LogShow[T] {
override def show(value: T): String = f(value)
}
}
import LogShow.create
implicit val StringShow: LogShow[String] = create(identity)
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.Remover
import scala.reflect.ClassTag
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)
(implicit
ct: ClassTag[T],
lg: LabelledGeneric.Aux[T, H],
rem: RemoverAll.Aux[H, HK, H1],
lsh: LogShow[H1]): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val clearedRecord = rem(record, hideFieldsWithKeys)
s"${ct.runtimeClass.getSimpleName}:\n${lsh.show(clearedRecord)}"
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] {type Out = Out0}
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicit def hconsLogShow[K <: Symbol, H, T <: HList](implicit
wt: Witness.Aux[K],
lshHead: LogShow[H],
lshTail: LogShow[T]): LogShow[FieldType[K, H] :: T] =
LogShow.create { value =>
s"${wt.value.name}: ${lshHead.show(value.head)}\n${lshTail.show(value.tail)}"
}
implicit val hnilLogShow: LogShow[HNil] = LogShow.create(_ => "")
//test
case class Address(country: String, street: String)
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
//could not find implicit value for parameter lg: shapeless.LabelledGeneric.Aux[T,H]
//[error] implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
println(implicitly[LogShow[Address]].show(Address("Ukraine", "Gorkogo")))
}
尝试
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.{Keys, Remover}
import shapeless.{::, DepFn2, HList, HNil, LabelledGeneric, Poly2, Witness}
import shapeless.record.Record
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], /*keys: Keys.Aux[H, K]*/ rem: RemoverAll.Aux[H, HK, H1]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val record1 = rem(record, hideFieldsWithKeys)
???
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] { type Out = Out0 }
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicitly[RemoverAll.Aux[Record.`'i -> Int, 's -> String, 'b -> Boolean`.T, Witness.`'s`.T :: Witness.`'i`.T :: HNil, Record.`'b -> Boolean`.T]]
替换行
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
和
import shapeless.syntax.singleton._
implicit val inst: LogShow[Address] = productsLogShow('country.narrow :: HNil)
'country
有类型 Symbol
而不是必需的单例类型 Witness.`'country`.T
.
我有下一段代码要用于类型 class 实例创建:
def productsLogShow[HK <: HList, T, H <: HList, K](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], keys: Keys.Aux[H, K]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
// ...
//filter somehow record and get a record without
// keys which are in 'hideFieldsWithKeys'
// ...
}
}
那么,如何过滤记录以及如何为 hideFieldsWithKeys
参数使用正确的类型?
更新: 根据 Dmitro 的回答应该可以工作的完整代码片段
object Main extends App {
trait LogShow[T] {
def show(value: T): String
}
object LogShow {
def apply[T: LogShow]: LogShow[T] = implicitly[LogShow[T]]
def create[T](f: T => String): LogShow[T] = new LogShow[T] {
override def show(value: T): String = f(value)
}
}
import LogShow.create
implicit val StringShow: LogShow[String] = create(identity)
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.Remover
import scala.reflect.ClassTag
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)
(implicit
ct: ClassTag[T],
lg: LabelledGeneric.Aux[T, H],
rem: RemoverAll.Aux[H, HK, H1],
lsh: LogShow[H1]): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val clearedRecord = rem(record, hideFieldsWithKeys)
s"${ct.runtimeClass.getSimpleName}:\n${lsh.show(clearedRecord)}"
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] {type Out = Out0}
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicit def hconsLogShow[K <: Symbol, H, T <: HList](implicit
wt: Witness.Aux[K],
lshHead: LogShow[H],
lshTail: LogShow[T]): LogShow[FieldType[K, H] :: T] =
LogShow.create { value =>
s"${wt.value.name}: ${lshHead.show(value.head)}\n${lshTail.show(value.tail)}"
}
implicit val hnilLogShow: LogShow[HNil] = LogShow.create(_ => "")
//test
case class Address(country: String, street: String)
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
//could not find implicit value for parameter lg: shapeless.LabelledGeneric.Aux[T,H]
//[error] implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
println(implicitly[LogShow[Address]].show(Address("Ukraine", "Gorkogo")))
}
尝试
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.{Keys, Remover}
import shapeless.{::, DepFn2, HList, HNil, LabelledGeneric, Poly2, Witness}
import shapeless.record.Record
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], /*keys: Keys.Aux[H, K]*/ rem: RemoverAll.Aux[H, HK, H1]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val record1 = rem(record, hideFieldsWithKeys)
???
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] { type Out = Out0 }
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicitly[RemoverAll.Aux[Record.`'i -> Int, 's -> String, 'b -> Boolean`.T, Witness.`'s`.T :: Witness.`'i`.T :: HNil, Record.`'b -> Boolean`.T]]
替换行
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
和
import shapeless.syntax.singleton._
implicit val inst: LogShow[Address] = productsLogShow('country.narrow :: HNil)
'country
有类型 Symbol
而不是必需的单例类型 Witness.`'country`.T
.