如何派生作用于特定子类型的 HList 的无形操作
How to derive a shapeless op which acts on an HList of a specific subtype
我试图创建一个无形操作,它作用于给定类型的对象的 HList。但是,我无法弄清楚如何使它在作为该对象子类型的对象的 HList 上工作。这是一个例子:
trait Transform[I, O] { def f: I => O }
trait Transformer[I, TH <: HList] {
type Out <: HList
def transform(input: I, transforms: TH): Out
}
object Transformer {
type Aux[I, Transforms <: HList, Out0] = Transformer[I, Transforms] { type Out = Out0 }
def apply[I, Transforms <: HList](implicit transformer: Transformer[I, Transforms]): Aux[I, Transforms, transformer.Out] = transformer
implicit def hnilTransformer[I]: Aux[I, HNil, HNil] =
new Transformer[I, HNil] {
type Out = HNil
override def transform(input: I, transforms: HNil): HNil = HNil
}
implicit def hconsTransformer[I, O, TIn <: HList, TOut <: HList]
(implicit t: Transformer.Aux[I, TIn, TOut]): Aux[I, Transform[I, O] :: TIn, O :: TOut] =
new Transformer[I, Transform[I, O] :: TIn] {
type Out = O :: TOut
override def transform(input: I, transforms: Transform[I, O] :: TIn): Out = {
transforms.head.f(input) :: t.transform(input, transforms.tail)
}
}
}
def applyTransforms[I, TH <: HList](transforms: TH)(input: I)
(implicit transformer: Transformer[I, TH]): transformer.Out = {
transformer.transform(input, transforms)
}
val double = new Transform[Int, Int] { def f = _ * 2 }
val int2Str = new Transform[Int, String] { def f = _.toString }
applyTransforms(double :: int2Str :: HNil)(4) // shouldBe 8 :: "4" :: HNil
trait SubTransform[I, O] extends Transform[I, O]
val doubleSub = new SubTransform[Int, Int] { def f = _ * 2 }
val int2StrSub = new SubTransform[Int, String] { def f = _.toString }
applyTransforms(doubleSub :: int2StrSub :: HNil)(4) // fails to compile
第一个 applyTransforms
编译成功但第二个失败并出现错误:
ShapelessSpec.scala:124: could not find implicit value for parameter transformer: Transformer[Int,shapeless.::[SubTransform[Int,Int],shapeless.::[SubTransform[Int,String],shapeless.HNil]]]
applyTransforms(doubleSub :: int2StrSub :: HNil)(4)
我怀疑问题出在 hconsTransformer
上,但我不明白为什么这不应该在 SubTransform
的范围内。
如果您希望它与 Transform
的子类型一起使用,请修改您的递归步骤
implicit def hconsTransformer[I, O, TIn <: HList, TOut <: HList, X]
(implicit t: Transformer.Aux[I, TIn, TOut], ev: X <:< Transform[I, O]): Aux[I, X :: TIn, O :: TOut] =
new Transformer[I, X :: TIn] {
type Out = O :: TOut
override def transform(input: I, transforms: X :: TIn): Out = {
transforms.head.f(input) :: t.transform(input, transforms.tail)
}
}
或使Transformer
相对于TH
逆变
trait Transformer[I, -TH <: HList] { ...
我试图创建一个无形操作,它作用于给定类型的对象的 HList。但是,我无法弄清楚如何使它在作为该对象子类型的对象的 HList 上工作。这是一个例子:
trait Transform[I, O] { def f: I => O }
trait Transformer[I, TH <: HList] {
type Out <: HList
def transform(input: I, transforms: TH): Out
}
object Transformer {
type Aux[I, Transforms <: HList, Out0] = Transformer[I, Transforms] { type Out = Out0 }
def apply[I, Transforms <: HList](implicit transformer: Transformer[I, Transforms]): Aux[I, Transforms, transformer.Out] = transformer
implicit def hnilTransformer[I]: Aux[I, HNil, HNil] =
new Transformer[I, HNil] {
type Out = HNil
override def transform(input: I, transforms: HNil): HNil = HNil
}
implicit def hconsTransformer[I, O, TIn <: HList, TOut <: HList]
(implicit t: Transformer.Aux[I, TIn, TOut]): Aux[I, Transform[I, O] :: TIn, O :: TOut] =
new Transformer[I, Transform[I, O] :: TIn] {
type Out = O :: TOut
override def transform(input: I, transforms: Transform[I, O] :: TIn): Out = {
transforms.head.f(input) :: t.transform(input, transforms.tail)
}
}
}
def applyTransforms[I, TH <: HList](transforms: TH)(input: I)
(implicit transformer: Transformer[I, TH]): transformer.Out = {
transformer.transform(input, transforms)
}
val double = new Transform[Int, Int] { def f = _ * 2 }
val int2Str = new Transform[Int, String] { def f = _.toString }
applyTransforms(double :: int2Str :: HNil)(4) // shouldBe 8 :: "4" :: HNil
trait SubTransform[I, O] extends Transform[I, O]
val doubleSub = new SubTransform[Int, Int] { def f = _ * 2 }
val int2StrSub = new SubTransform[Int, String] { def f = _.toString }
applyTransforms(doubleSub :: int2StrSub :: HNil)(4) // fails to compile
第一个 applyTransforms
编译成功但第二个失败并出现错误:
ShapelessSpec.scala:124: could not find implicit value for parameter transformer: Transformer[Int,shapeless.::[SubTransform[Int,Int],shapeless.::[SubTransform[Int,String],shapeless.HNil]]]
applyTransforms(doubleSub :: int2StrSub :: HNil)(4)
我怀疑问题出在 hconsTransformer
上,但我不明白为什么这不应该在 SubTransform
的范围内。
如果您希望它与 Transform
implicit def hconsTransformer[I, O, TIn <: HList, TOut <: HList, X]
(implicit t: Transformer.Aux[I, TIn, TOut], ev: X <:< Transform[I, O]): Aux[I, X :: TIn, O :: TOut] =
new Transformer[I, X :: TIn] {
type Out = O :: TOut
override def transform(input: I, transforms: X :: TIn): Out = {
transforms.head.f(input) :: t.transform(input, transforms.tail)
}
}
或使Transformer
相对于TH
trait Transformer[I, -TH <: HList] { ...