[英]Map single type HList to HList of target types
I have trait-marker 我有特征标记
trait TypedTrait {
type TYPE
}
and the realization 和实现
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
And I want to map HList
of String
into HList
of TypedString
in accordance with TypedString
's type parameters. 我要地图HList
的String
到HList
的TypedString
按照TypedString
的类型参数。
The simplest way is to create convert
method (as described in Shapeless map HList depending on target types ): 最简单的方法是创建convert
方法(如Shapeless映射HList中所述, 具体取决于目标类型 ):
val list = "Hello" :: "world" :: HNil
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[TypedString[Int] :: TypedString[Boolean] :: HNil](list)
But I'd like to avoid redundant parameterization and use something like this: 但是我想避免多余的参数化,并使用类似这样的东西:
val mapped: TypedString[Int] :: TypedString[Boolean] :: HNil =
convert[Int :: Boolean :: HNil](list)
Complete code example for the first solution: 第一个解决方案的完整代码示例:
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)
You can achive this by having three HList
type arguments in Convert
: 您可以通过在Convert
使用三个HList
类型参数来实现此HList
:
HList
passed to convert
(eg, String :: String :: HNil
) 传递给convert
的实际HList
的类型(例如String :: String :: HNil
) Int :: Boolean :: HNil
) 用户指定的类型参数(例如, Int :: Boolean :: HNil
) HList
wrapped in TypedString
: eg, TypedString[Int] :: TypedString[Boolean] :: HNil
. 输出类型–基本上是包装在TypedString
的指定HList
:例如, TypedString[Int] :: TypedString[Boolean] :: HNil
。 The output type can be completely calculated from the prescribed HList
, so I'd use the Aux
pattern commonly employed with shapeless
code: 可以从指定的HList
完全计算输出类型,因此我将使用shapeless
代码常用的Aux
模式 :
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)
Result: 结果:
scala> mapped
res3: shapeless.::[com.Main.TypedString[Int],shapeless.::[com.Main.TypedString[String],shapeless.HNil]] = TypedString(Hello) :: TypedString(world) :: HNil
I believe it may be possible to achieve this using some operations provided with shapeless
( shapeless.ops.hlist.Mapped
, shapeless.ops.hlist.HKernel
, or shapeless.ops.hlist.RightFolder
look appropriate), but I don't know how to write a Poly
function, that takes a type argument and a normal argument. 我认为可能可以使用shapeless
提供的一些操作来实现此目的( shapeless.ops.hlist.Mapped
, shapeless.ops.hlist.HKernel
或shapeless.ops.hlist.RightFolder
看起来合适),但我不知道如何编写一个Poly
函数,该函数需要一个类型参数和一个普通参数。 Any tips would be welcome. 任何提示都将受到欢迎。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.