假设我有一个abitrary KList,为了参数的缘故,它有类型构造函数Option [_],即;
type Example = Option[Int] :: Option[String] :: HNil
有没有办法可以检索由类型参数组成的Hlist?
type Params = Int :: String :: HNil
因此,例如,我可以定义某种任意的getOrElse方法
getOrElse(ex:Example, default:Params):Params
现在我正在寻找可能具有这种形式的东西(或类似于我建议的类型结构可能不可行)。
case class MyOptionList[L <: HList](maybes:L) {
type Concrete = {somehow the hlist params types as an Hlist}
def getOrElse(default:Concrete):Concrete = ???
}
答案 0 :(得分:7)
我不是Miles,但是有可能通过Shapeless的Comapped
来完成你想要做的非常优雅的事情:{/ 1}:
import shapeless._, ops.hlist.Comapped
case class MyOptionList[L <: HList, C <: HList](maybes: L)(
implicit val comapped: Comapped.Aux[L, Option, C]
) {
def getOrElse(default: C): C = default // Not a useful implementation
}
然后:
scala> val x: Int :: HNil = MyOptionList(Option(1) :: HNil).getOrElse(2 :: HNil)
x: shapeless.::[Int,shapeless.HNil] = 2 :: HNil
请注意,在某些情况下,将约束放在方法上会更方便:
case class MyOptionList[L <: HList](maybes: L) {
def getOrElse[C <: HList: ({ type l[x] = Comapped.Aux[L, Option, x] })#l](
default: C
): C = default
}
此处的用法相同,但您在案例类中没有额外的类型参数。如果您想使用此方法但限制MyOptionList
的创建以禁止非Option
成员,则可以在其类型参数列表中使用L <: HList: *->*[Option]#λ
。
答案 1 :(得分:4)
@MilesSabin可能会出现一个更优雅的答案,但你可以手工递归地构建这个,就像许多无形的内部事物一样:
sealed trait GetOrElse[L <: HList] {
type Concrete <: HList
def getOrElse(ex: L, default: Concrete): Concrete
}
object GetOrElse {
implicit def nil = new GetOrElse[HNil]{
type Concrete = HNil
def getOrElse(ex: HNil, default: HNil) = HNil
}
implicit def cons[H, T <: HList](implicit tl: GetOrElse[T]) =
new GetOrElse[Option[H] :: T]{
type Concrete = H :: tl.Concrete
def getOrElse(ex: Option[H] :: T, default: Concrete) =
ex.head.getOrElse(default.head) ::
tl.getOrElse(ex.tail, default.tail)
}
def apply[L <: HList](implicit goe: GetOrElse[L])
: GetOrElse[L]{type Concrete = goe.Concrete} = goe
}
case class MyOptionList[L <: HList, C](maybes:L)(
implicit goe: GetOrElse[L]{type Concrete = C}) {
def getOrElse(default:C):C = goe.getOrElse(maybes, default)
}
(可能使用类型成员而不是类型参数,但是我对这些类型信息何时被吃掉感到困惑,所以我倾向于在任何地方使用类型参数)