Вы можете сделать это с помощью специального типа, который свидетельствует о том, что существует только один TB
, а все остальные элементы - TA
. Если вы планируете создать этот список индуктивно, вы увидите, что вам нужно обрабатывать два случая: либо все, что вы видели до сих пор, это TA
(что мы можем наблюдать с помощью ToList[T, TA]
), а текущий элемент - TB
, или вы уже видели один TB
и текущий элемент является TA
:
import shapeless._, ops.hlist.{ ToList }
trait T
case class TA() extends T
case class TB() extends T
trait UniqueTB[L <: HList] extends DepFn1[L] {
type Out = TB
def apply(l: L): TB
}
object UniqueTB {
def apply[L <: HList](implicit utb: UniqueTB[L]): UniqueTB[L] = utb
def getTB[L <: HList](l: L)(implicit utb: UniqueTB[L]): TB = utb(l)
implicit def firstTB[T <: HList](
implicit tl: ToList[T, TA]
): UniqueTB[TB :: T] = new UniqueTB[TB :: T] {
def apply(l: TB :: T): TB = l.head
}
implicit def afterTB[T <: HList](
implicit utb: UniqueTB[T]
): UniqueTB[TA :: T] = new UniqueTB[TA :: T] {
def apply(l: TA :: T): TB = utb(l.tail)
}
}
и потом:
scala> UniqueTB[TB :: HNil]
res0: UniqueTB[shapeless.::[TB,shapeless.HNil]] = [email protected]
scala> UniqueTB[TA :: TB :: HNil]
res1: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.HNil]]] = [email protected]
scala> UniqueTB[TA :: TB :: TA :: HNil]
res2: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.::[TA,shapeless.HNil]]]] = [email protected]
scala> UniqueTB[TB :: HNil]
res3: UniqueTB[shapeless.::[TB,shapeless.HNil]] = [email protected]
scala> UniqueTB[TA :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TA,shapeless.HNil]]
UniqueTB[TA :: HNil]
^
scala> UniqueTB[HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.HNil]
UniqueTB[HNil]
^
scala> UniqueTB[TB :: TB :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TB,shapeless.::[TB,shapeless.HNil]]]
UniqueTB[TB :: TB :: HNil]
^
Я дал класс тип операции, которая возвращает TB
, но если вам не нужно, чтобы вы могли оставить его методом-le песчаники
Другие типы, допустимые в hlist? –
Нет, только те, которые расширяют T (и, вероятно, никогда не будет никаких других типов, кроме TA и TB). –