将单一类型 HList 映射到目标类型的 HList
Map single type HList to HList of target types
我有特征标记
trait TypedTrait {
type TYPE
}
和实现
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
并且我想根据TypedString
的类型参数将String
的HList
映射到TypedString
的HList
。
最简单的方法是创建 convert
方法(如 中所述):
val list = "Hello" :: "world" :: HNil
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[TypedString[Int] :: TypedString[Boolean] :: HNil](list)
但我想避免冗余参数化并使用这样的东西:
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[Int :: Boolean :: HNil](list)
第一个解决方案的完整代码示例:
import shapeless._
trait TypedTrait {
type TYPE
}
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
trait Convert[I <: HList, O <: HList] { def apply(i: I): O }
object Convert extends LowPriorityConvertInstances {
implicit val convertHNil: Convert[HNil, HNil] = new Convert[HNil, HNil] {
def apply(i: HNil): HNil = i
}
implicit def convertHConsTS[TS, T <: HList, TO <: HList](implicit
c: Convert[T, TO]
): Convert[String :: T, TypedString[TS] :: TO] =
new Convert[String :: T, TypedString[TS] :: TO] {
def apply(i: String :: T): TypedString[TS] :: TO = TypedString[TS](i.head) :: c(i.tail)
}
}
sealed class LowPriorityConvertInstances {
implicit def convertHCons[H, T <: HList, TO <: HList](implicit
c: Convert[T, TO]
): Convert[H :: T, H :: TO] = new Convert[H :: T, H :: TO] {
def apply(i: H :: T): H :: TO = i.head :: c(i.tail)
}
}
class PartiallyAppliedConvert[O <: HList] {
def apply[I <: HList](i: I)(implicit c: Convert[I, O]): O = c(i)
}
def convert[O <: HList]: PartiallyAppliedConvert[O] =
new PartiallyAppliedConvert[O]
val list = "Hello" :: "world" :: HNil
val mapped: TypedString[Int] :: TypedString[String] :: HNil =
convert[TypedString[Int] :: TypedString[String] :: HNil](list)
您可以通过在 Convert
中设置三个 HList
类型参数来实现此目的:
- 实际
HList
传递给 convert
的类型(例如,String :: String :: HNil
)
- 用户指定的类型参数(例如
Int :: Boolean :: HNil
)
- 输出类型——基本上是
HList
包裹在 TypedString
中的规定:例如,TypedString[Int] :: TypedString[Boolean] :: HNil
.
输出类型完全可以根据规定的HList
计算出来,所以我会使用shapeless
常用的代码:
trait Convert[In <: HList, Prescribed <: HList] {
type Out <: HList
def apply(i: In): Out
}
object Convert {
type Aux[I <: HList, P <: HList, O <: HList] = Convert[I, P] { type Out = O }
// Adapt the implicits accordingly.
// The low priority one is left as an exercise to the reader.
implicit val convertHNil: Convert.Aux[HNil, HNil, HNil] =
new Convert[HNil, HNil] {
type Out = HNil
def apply(i: HNil): HNil = i
}
implicit def convertHConsTS[TS, TI <: HList, TP <: HList, TO <: HList](implicit
c: Convert.Aux[TI, TP, TO]
): Convert.Aux[String :: TI, TS :: TP, TypedString[TS] :: TO] =
new Convert[String :: TI, TS :: TP] {
type Out = TypedString[TS] :: TO
def apply(i: String :: TI): TypedString[TS] :: TO =
TypedString[TS](i.head) :: c(i.tail)
}
}
class PartiallyAppliedConvert[P <: HList] {
def apply[I <: HList](i: I)(implicit c: Convert[I, P]): c.Out = c(i)
}
def convert[O <: HList]: PartiallyAppliedConvert[O] =
new PartiallyAppliedConvert[O]
val list = "Hello" :: "world" :: HNil
val mapped = convert[Int :: String :: HNil](list)
结果:
scala> mapped
res3: shapeless.::[com.Main.TypedString[Int],shapeless.::[com.Main.TypedString[String],shapeless.HNil]] = TypedString(Hello) :: TypedString(world) :: HNil
我相信使用 shapeless
提供的一些操作可以实现这一点(shapeless.ops.hlist.Mapped
、shapeless.ops.hlist.HKernel
或 shapeless.ops.hlist.RightFolder
看起来很合适),但我不知道' 知道如何编写一个 Poly
函数,它接受一个类型参数和一个普通参数。欢迎任何提示。
我有特征标记
trait TypedTrait {
type TYPE
}
和实现
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
并且我想根据TypedString
的类型参数将String
的HList
映射到TypedString
的HList
。
最简单的方法是创建 convert
方法(如
val list = "Hello" :: "world" :: HNil
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[TypedString[Int] :: TypedString[Boolean] :: HNil](list)
但我想避免冗余参数化并使用这样的东西:
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[Int :: Boolean :: HNil](list)
第一个解决方案的完整代码示例:
import shapeless._
trait TypedTrait {
type TYPE
}
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
trait Convert[I <: HList, O <: HList] { def apply(i: I): O }
object Convert extends LowPriorityConvertInstances {
implicit val convertHNil: Convert[HNil, HNil] = new Convert[HNil, HNil] {
def apply(i: HNil): HNil = i
}
implicit def convertHConsTS[TS, T <: HList, TO <: HList](implicit
c: Convert[T, TO]
): Convert[String :: T, TypedString[TS] :: TO] =
new Convert[String :: T, TypedString[TS] :: TO] {
def apply(i: String :: T): TypedString[TS] :: TO = TypedString[TS](i.head) :: c(i.tail)
}
}
sealed class LowPriorityConvertInstances {
implicit def convertHCons[H, T <: HList, TO <: HList](implicit
c: Convert[T, TO]
): Convert[H :: T, H :: TO] = new Convert[H :: T, H :: TO] {
def apply(i: H :: T): H :: TO = i.head :: c(i.tail)
}
}
class PartiallyAppliedConvert[O <: HList] {
def apply[I <: HList](i: I)(implicit c: Convert[I, O]): O = c(i)
}
def convert[O <: HList]: PartiallyAppliedConvert[O] =
new PartiallyAppliedConvert[O]
val list = "Hello" :: "world" :: HNil
val mapped: TypedString[Int] :: TypedString[String] :: HNil =
convert[TypedString[Int] :: TypedString[String] :: HNil](list)
您可以通过在 Convert
中设置三个 HList
类型参数来实现此目的:
- 实际
HList
传递给convert
的类型(例如,String :: String :: HNil
) - 用户指定的类型参数(例如
Int :: Boolean :: HNil
) - 输出类型——基本上是
HList
包裹在TypedString
中的规定:例如,TypedString[Int] :: TypedString[Boolean] :: HNil
.
输出类型完全可以根据规定的HList
计算出来,所以我会使用shapeless
常用的
trait Convert[In <: HList, Prescribed <: HList] {
type Out <: HList
def apply(i: In): Out
}
object Convert {
type Aux[I <: HList, P <: HList, O <: HList] = Convert[I, P] { type Out = O }
// Adapt the implicits accordingly.
// The low priority one is left as an exercise to the reader.
implicit val convertHNil: Convert.Aux[HNil, HNil, HNil] =
new Convert[HNil, HNil] {
type Out = HNil
def apply(i: HNil): HNil = i
}
implicit def convertHConsTS[TS, TI <: HList, TP <: HList, TO <: HList](implicit
c: Convert.Aux[TI, TP, TO]
): Convert.Aux[String :: TI, TS :: TP, TypedString[TS] :: TO] =
new Convert[String :: TI, TS :: TP] {
type Out = TypedString[TS] :: TO
def apply(i: String :: TI): TypedString[TS] :: TO =
TypedString[TS](i.head) :: c(i.tail)
}
}
class PartiallyAppliedConvert[P <: HList] {
def apply[I <: HList](i: I)(implicit c: Convert[I, P]): c.Out = c(i)
}
def convert[O <: HList]: PartiallyAppliedConvert[O] =
new PartiallyAppliedConvert[O]
val list = "Hello" :: "world" :: HNil
val mapped = convert[Int :: String :: HNil](list)
结果:
scala> mapped
res3: shapeless.::[com.Main.TypedString[Int],shapeless.::[com.Main.TypedString[String],shapeless.HNil]] = TypedString(Hello) :: TypedString(world) :: HNil
我相信使用 shapeless
提供的一些操作可以实现这一点(shapeless.ops.hlist.Mapped
、shapeless.ops.hlist.HKernel
或 shapeless.ops.hlist.RightFolder
看起来很合适),但我不知道' 知道如何编写一个 Poly
函数,它接受一个类型参数和一个普通参数。欢迎任何提示。