2015-09-03 18 views
8

Sto essenzialmente cercando l'opposto della classe di tipo Prepend[A, B].Divisione di una lista H concatenata utilizzando Prepend [A, B]

Se ho qualcosa di simile:

type A = String :: Int :: HNil 
type B = Boolean :: Double :: HNil 

val a: A = "a" :: 1 :: HNil 
val b: B = false :: 2.1 :: HNil 

scala> val ab = a ++ b 
ab: shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.::[Double,shapeless.HNil]]]] = a :: 1 :: false :: 2.1 :: HNil 

ho un HLista di tipo A ed un HListb di tipo B, posso trovare un prepend: Prepend[A, B] tale che io possa concatenare con a ++ b.

Ma se ho un HListab di tipo prepend.Out, come posso estrarre l'originale A e B? Non riesco a trovare una classe di tipo che faccia il lavoro, e forse non ce n'è uno. Sembra che avrei bisogno di qualcosa come trait Cut[A <: HList, B <: HList, c <: HList] che testimonia che C è stato creato pre-pending A a B, anche se non sono sicuro di come andrei a generare testimoni.

Molto approssimativamente come:

def Cut[A <: HList, B <: HList, C <: HList](c: C)(implicit cut: Cut[A, B, C]): (A, B) = ??? 
+0

puoi prendere in considerazione [tagging] (http://eed3si9n.com/learning-scalaz/Tagged+type.html) (avviso: i tipi con tag di scalaz non sono così cool come lo erano) di ogni elemento con qualche tipo unico (generalo come path-dependent), come 'val a: A =" a ":: 1 :: HNil taggato; val a: B = "a" :: 1 :: HNil tagged' e quindi basta filtrare ogni lista per tipo. solo un'idea - non ho controllato :) – dk14

risposta

5

È possibile farlo abbastanza semplicemente con Split:

import shapeless._, ops.hlist.{ Length, Prepend, Split } 

class UndoPrependHelper[A <: HList, B <: HList, C <: HList, N <: Nat] { 
    def apply(c: C)(implicit split: Split.Aux[C, N, A, B]): (A, B) = split(c) 
} 

def undoPrepend[A <: HList, B <: HList](implicit 
    prepend: Prepend[A, B], 
    length: Length[A] 
) = new UndoPrependHelper[A, B, prepend.Out, length.Out] 

E poi:

scala> type A = Int :: String :: Symbol :: HNil 
defined type alias A 

scala> type B = List[Int] :: Option[Double] :: HNil 
defined type alias B 

scala> type C = Int :: String :: Symbol :: List[Int] :: Option[Double] :: HNil 
defined type alias C 

scala> val a: A = 1 :: "foo" :: 'bar :: HNil 
a: A = 1 :: foo :: 'bar :: HNil 

scala> val b: B = List(1, 2, 3) :: Option(0.0) :: HNil 
b: B = List(1, 2, 3) :: Some(0.0) :: HNil 

scala> val c: C = a ++ b 
c: C = 1 :: foo :: 'bar :: List(1, 2, 3) :: Some(0.0) :: HNil 

scala> val (newA: A, newB: B) = undoPrepend[A, B].apply(c) 
newA: A = 1 :: foo :: 'bar :: HNil 
newB: B = List(1, 2, 3) :: Some(0.0) :: HNil 

I recently added un "undo" operazione per la Remove type class, e potrebbe avere senso avere som simile incorporato in Prepend.

Problemi correlati