【发布时间】:2016-08-10 11:31:08
【问题描述】:
我有特征标记
trait TypedTrait {
type TYPE
}
以及实现
case class TypedString[U](value: String) extends TypedTrait {
type TYPE = U
}
并且我想根据TypedString的类型参数将String的HList映射成TypedString的HList。
最简单的方法是创建convert 方法(如Shapeless map HList depending on target types 中所述):
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)
【问题讨论】: