从 Shapeless / scala 中的联合中获取 SelectAll



>我有一个由两个HList创建的Union,假设EF。从这个Union,我想找回一个类型为E的新HList。它不一定具有与原始列表相同的值,但我不在乎,我只想要一个类型正确的HList

在实践中,我想要的可以总结为一个函数: def selectFromUnion[E <: HList, F <: HList](u: Union[E, F]): SelectAll[u.Out, E] = ???

有人知道我该如何实现吗?或者,如果无形已经有办法了?

编辑:如果我能更精确一点,我想要一个证明 2HList的联合包含原始HLists 的类型。我们可以将原始问题简化为搜索:

implicit def selectFromUnion[E, T <: HList, F <: HList](implicit u: Union[E :: T, F]): Selector[u.Out, E] = ???

可悲的是,我仍然不知道如何做到这一点。

因此,我找到了一个适合我的情况的解决方案,通过声明我自己的Union(复制/粘贴获胜)并添加一个属性来提供SelectAll实例

trait SelectableUnion[L <: HList, M <: HList] extends DepFn2[L, M] with Serializable {
type Out <: HList
def selectL: SelectAll[Out, L]
def selectM: SelectAll[Out, M]
}
trait LowPriorityUnion {
type Aux[L <: HList, M <: HList, Out0 <: HList] = SelectableUnion[L, M] {type Out = Out0}
}
object SelectableUnion extends LowPriorityUnion {
def apply[L <: HList, M <: HList](implicit union: SelectableUnion[L, M]): Aux[L, M, union.Out] = union
// let ∅ ∪ M = M
implicit def hlistUnion[M <: HList]: Aux[HNil, M, M] =
new SelectableUnion[HNil, M] {
type Out = M
def apply(l: HNil, m: M): Out = m
override def selectL: SelectAll[M, HNil] = SelectAll.hnilSelectAll
override def selectM: SelectAll[M, M] = new SelectAll[M, M] {
override def apply(t: M): M = t
}
}
// let (H :: T) ∪ M  =  H :: (T ∪ M) when H ∉ M
implicit def hlistUnion1[H, T <: HList, M <: HList]
(implicit
u: SelectableUnion[T, M],
f: FilterNot.Aux[M, H, M]
): Aux[H :: T, M, H :: u.Out] =
new SelectableUnion[H :: T, M] {
type Out = H :: u.Out
def apply(l: H :: T, m: M): Out = l.head :: u(l.tail, m)
override def selectL: SelectAll[::[H, u.Out], ::[H, T]] = new SelectAll[H :: u.Out, H :: T] {
override def apply(t: H :: u.Out): H :: T = (t.head) :: u.selectL(t.tail)
}
override def selectM: SelectAll[::[H, u.Out], M] = new SelectAll[H :: u.Out, M] {
override def apply(t: ::[H, u.Out]): M = u.selectM.apply(t.tail)
}
}
// let (H :: T) ∪ M  =  H :: (T ∪ (M - H)) when H ∈ M
implicit def hlistUnion2[H, T <: HList, M <: HList, MR <: HList]
(implicit
r: Remove.Aux[M, H, (H, MR)],
u: SelectableUnion[T, MR]
): Aux[H :: T, M, H :: u.Out] =
new SelectableUnion[H :: T, M] {
type Out = H :: u.Out
def apply(l: H :: T, m: M): Out = l.head :: u(l.tail, r(m)._2)
override def selectL: SelectAll[::[H, u.Out], ::[H, T]] = new SelectAll[H :: u.Out, H :: T] {
override def apply(t: H :: u.Out): H :: T = (t.head) :: u.selectL(t.tail)
}
override def selectM: SelectAll[::[H, u.Out], M] = new SelectAll[H :: u.Out, M] {
override def apply(t: ::[H, u.Out]): M = r.reinsert(t.head, u.selectM(t.tail))
}
}
}

然后你可以写

def selectFromUnion[E <: HList, F <: HList](u: SelectableUnion[E, F]): SelectAll[u.Out, E] = u.selectL

最新更新