Es gibt eine Reihe von Möglichkeiten, wie Sie dies tun könnte, aber ich mit einem benutzerdefinierten Typ Klasse gehen würde:
import shapeless._
trait RowSelect[L <: HList] extends DepFn2[L, Int] {
type Row <: HList
type Out = Option[Row]
}
object RowSelect {
def select[L <: HList](l: L, i: Int)(implicit rs: RowSelect[L]): rs.Out = rs(l, i)
type Aux[L <: HList, Row0 <: HList] = RowSelect[L] { type Row = Row0 }
implicit val hnilRowSelect: Aux[HNil, HNil] = new RowSelect[HNil] {
type Row = HNil
def apply(l: HNil, i: Int): Option[HNil] = Some(HNil)
}
implicit def hconsRowSelect[A, T <: HList](implicit
trs: RowSelect[T]
): Aux[List[A] :: T, A :: trs.Row] = new RowSelect[List[A] :: T] {
type Row = A :: trs.Row
def apply(l: List[A] :: T, i: Int): Option[A :: trs.Row] = for {
h <- l.head.lift(i)
t <- trs(l.tail, i)
} yield h :: t
}
}
die wie folgt funktioniert:
scala> println(RowSelect.select(a, 0))
Some(1 :: a :: true :: HNil)
scala> println(RowSelect.select(a, 1))
Some(2 :: b :: false :: HNil)
scala> println(RowSelect.select(a, 2))
Some(3 :: c :: true :: HNil)
scala> println(RowSelect.select(a, 3))
None
A RowSelect
Instanz für L
Zeugen, dass L
ist eine Hlist mit allen List
Elemente, und bietet eine Operation, die optional das Element an einem angegebenen Index von jedem List
auswählt.
Sie sollten die gleiche Sache mit NatTRel
oder einer Kombination aus ConstMapper
und ZipWith
und einem Poly2
, sondern eine individuelle Typklasse bündelt alles gut zusammen und erlaubt in vielen Fällen bequemer Kompositionalität bewerkstelligen können.
Zum Beispiel, in diesem Fall die Lösung Ihrer Bonus-Frage ziemlich werden kann in Bezug auf RowSelect
ohne weiteres geschrieben:
def allRows[L <: HList](l: L)(implicit rs: RowSelect[L]): List[rs.Row] =
Stream.from(0).map(rs(l, _).toList).takeWhile(_.nonEmpty).flatten.toList
Und dann:
scala> allRows(a).foreach(println)
1 :: a :: true :: HNil
2 :: b :: false :: HNil
3 :: c :: true :: HNil
Und ähnlich, wenn Sie konvertieren möchten diese hlists zu Tupeln:
def allRows[L <: HList, R <: HList](l: L)(implicit
rs: RowSelect.Aux[L, R],
tp: ops.hlist.Tupler[R]
): List[tp.Out] =
Stream.from(0).map(rs(l, _).map(tp(_)).toList).takeWhile(_.nonEmpty).flatten.toList
Welche gibt yo u:
scala> allRows(a)
res7: List[(Int, String, Boolean)] = List((1,a,true), (2,b,false), (3,c,true))
Und so weiter.
Einige verwandte Fragen zu polymorphen Funktionen: http://stackoverflow.com/questions/39628068/passing-an-extra-argument-into-a-polymorphe-function http://stackoverflow.com/questions/39628022/using -a-polymorphe Funktion zum Extrahieren eines Objekts aus Optionen –