Shapeless - 使用 HList 应用工厂函数
Shapeless - Apply factory functions with HList
我有一堆工厂函数,它们都采用相同的参数和 return 不同的类型。目前我都显式调用它们,但它非常冗长,我想将工厂泛化为 HList
并通过映射 HList
.
来调用每个工厂
case class Endpoint[A](a: A)
case class Factory[Ret](f: Int => Endpoint[Ret])
val factories = Factory[Int](a => Endpoint(a)) :: Factory[String](a => Endpoint(a.toString)) :: HNil
我定义了一个 Poly1
以便我可以映射我的 HList
并为每个元素应用 f
case class ApplyFactory(param: Int) extends Poly1 {
implicit def generic[A]: Case.Aux[Factory[A], Endpoint[A]] =
at((factory: Factory[A]) => factory.f(param))
}
val endpoints = factories.map(ApplyFactory(5))
问题是could not find implicit value for parameter mapper
。将 ApplyFactory
更改为对象会使代码编译。如果 Poly
被定义为 class 而不是对象,我该如何映射到 HList
?或者是否有更好的模式来应用具有给定参数集的 HList
函数,并 return 使用结果 HList
新的 HList
?
不用担心 Poly
,只需手动实现您需要的任何自定义地图:
trait FactoryMap[L <: HList] {
type Out <: HList
def map(i: Int, h: L): Out
}
object FactoryMap {
type Aux[L <: HList, O <: HList] = FactoryMap[L] { type Out = O }
implicit def caseNil: Aux[HNil, HNil] = new FactoryMap[HNil] {
type Out = HNil
def map(i: Int, l: HNil): HNil = l
}
implicit def caseCons[T <: HList, O <: HList]
(implicit ev: Aux[T, O]) = new FactoryMap[Factory[Int] :: T] {
type Out = Endpoint[Int] :: O
def map(i: Int, l: Factory[Int] :: T): Endpoint[Int] :: O = {
val (h :: t) = l
h.f(i) :: ev.map(i, t)
}
}
}
implicit case class MyMap[L <: HList](l: L) {
def customMap[O <: HList](i: Int)(implicit ev: FactoryMap.Aux[L, O]): O =
ev.map(i, l)
}
与 Poly
不同,将上述内容推广到任何 Ret
(而不是像我那样 Ret = Int
)相对简单。
我有一堆工厂函数,它们都采用相同的参数和 return 不同的类型。目前我都显式调用它们,但它非常冗长,我想将工厂泛化为 HList
并通过映射 HList
.
case class Endpoint[A](a: A)
case class Factory[Ret](f: Int => Endpoint[Ret])
val factories = Factory[Int](a => Endpoint(a)) :: Factory[String](a => Endpoint(a.toString)) :: HNil
我定义了一个 Poly1
以便我可以映射我的 HList
并为每个元素应用 f
case class ApplyFactory(param: Int) extends Poly1 {
implicit def generic[A]: Case.Aux[Factory[A], Endpoint[A]] =
at((factory: Factory[A]) => factory.f(param))
}
val endpoints = factories.map(ApplyFactory(5))
问题是could not find implicit value for parameter mapper
。将 ApplyFactory
更改为对象会使代码编译。如果 Poly
被定义为 class 而不是对象,我该如何映射到 HList
?或者是否有更好的模式来应用具有给定参数集的 HList
函数,并 return 使用结果 HList
新的 HList
?
不用担心 Poly
,只需手动实现您需要的任何自定义地图:
trait FactoryMap[L <: HList] {
type Out <: HList
def map(i: Int, h: L): Out
}
object FactoryMap {
type Aux[L <: HList, O <: HList] = FactoryMap[L] { type Out = O }
implicit def caseNil: Aux[HNil, HNil] = new FactoryMap[HNil] {
type Out = HNil
def map(i: Int, l: HNil): HNil = l
}
implicit def caseCons[T <: HList, O <: HList]
(implicit ev: Aux[T, O]) = new FactoryMap[Factory[Int] :: T] {
type Out = Endpoint[Int] :: O
def map(i: Int, l: Factory[Int] :: T): Endpoint[Int] :: O = {
val (h :: t) = l
h.f(i) :: ev.map(i, t)
}
}
}
implicit case class MyMap[L <: HList](l: L) {
def customMap[O <: HList](i: Int)(implicit ev: FactoryMap.Aux[L, O]): O =
ev.map(i, l)
}
与 Poly
不同,将上述内容推广到任何 Ret
(而不是像我那样 Ret = Int
)相对简单。