Skip to content

Instantly share code, notes, and snippets.

@channingwalton
Last active August 29, 2015 14:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save channingwalton/11138259 to your computer and use it in GitHub Desktop.
Save channingwalton/11138259 to your computer and use it in GitHub Desktop.
Replacing boilerplate with shapeless
case class Foo[T](x: T) {
def map[B](f: T => B) = Foo(f(x))
}
object OldWay {
def combineLatest[T1, T2](e1: Foo[T1], e2: Foo[T2]): Foo[(T1, T2)] = Foo((e1.x, e2.x))
def combineLatest[T1, T2, T3](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3]): Foo[(T1, T2, T3)] =
combineLatest(combineLatest(e1, e2), e3) map {
case ((v1, v2), v3) ⇒ (v1, v2, v3)
}
def combineLatest[T1, T2, T3, T4](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4]): Foo[(T1, T2, T3, T4)] =
combineLatest(combineLatest(e1, e2, e3), e4) map {
case ((v1, v2, v3), v4) ⇒ (v1, v2, v3, v4)
}
def combineLatest[T1, T2, T3, T4, T5](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5]): Foo[(T1, T2, T3, T4, T5)] =
combineLatest(combineLatest(e1, e2, e3, e4), e5) map {
case ((v1, v2, v3, v4), v5) ⇒ (v1, v2, v3, v4, v5)
}
def combineLatest[T1, T2, T3, T4, T5, T6](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6]): Foo[(T1, T2, T3, T4, T5, T6)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5), e6) map {
case ((v1, v2, v3, v4, v5), v6) ⇒ (v1, v2, v3, v4, v5, v6)
}
def combineLatest[T1, T2, T3, T4, T5, T6, T7](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6], e7: Foo[T7]): Foo[(T1, T2, T3, T4, T5, T6, T7)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5, e6), e7) map {
case ((v1, v2, v3, v4, v5, v6), v7) ⇒ (v1, v2, v3, v4, v5, v6, v7)
}
def combineLatest[T1, T2, T3, T4, T5, T6, T7, T8](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6], e7: Foo[T7], e8: Foo[T8]): Foo[(T1, T2, T3, T4, T5, T6, T7, T8)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5, e6, e7), e8) map {
case ((v1, v2, v3, v4, v5, v6, v7), v8) ⇒ (v1, v2, v3, v4, v5, v6, v7, v8)
}
def combineLatest[T1, T2, T3, T4, T5, T6, T7, T8, T9](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6], e7: Foo[T7], e8: Foo[T8], e9: Foo[T9]): Foo[(T1, T2, T3, T4, T5, T6, T7, T8, T9)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5, e6, e7, e8), e9) map {
case ((v1, v2, v3, v4, v5, v6, v7, v8), v9) ⇒ (v1, v2, v3, v4, v5, v6, v7, v8, v9)
}
def combineLatest[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6], e7: Foo[T7], e8: Foo[T8], e9: Foo[T9], e10: Foo[T10]): Foo[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5, e6, e7, e8, e9), e10) map {
case ((v1, v2, v3, v4, v5, v6, v7, v8, v9), v10) ⇒ (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
}
def combineLatest[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11](e1: Foo[T1], e2: Foo[T2], e3: Foo[T3], e4: Foo[T4], e5: Foo[T5], e6: Foo[T6], e7: Foo[T7], e8: Foo[T8], e9: Foo[T9], e10: Foo[T10], e11: Foo[T11]): Foo[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)] =
combineLatest(combineLatest(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10), e11) map {
case ((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10), v11) ⇒ (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
}
}
object TheShapelessWay {
import shapeless._
import syntax.std.tuple._
import ops.hlist._
object combine extends Poly {
implicit def caseFoo[A, B <: HList] = use((f1: Foo[A], f2: Foo[B]) => Foo(f1.x :: f2.x))
}
def combineHLatest[L <: HList, R <: HList](l: L)(implicit r: RightFolder.Aux[L, Foo[HNil], combine.type, Foo[R]],t: Tupler[R]): Foo[Tupler[R]#Out] =
l.foldRight(Foo(HNil: HNil))(combine).map(_.tupled)
def combineToCC[L <: HList, R <: HList, T](l: L, gen: Generic[T])(implicit r: RightFolder.Aux[L, Foo[HNil], combine.type, Foo[R]], ev: R =:= gen.Repr): Foo[T] =
l.foldRight(Foo(HNil: HNil))(combine).map(gen.from(_))
}
object UseIt extends App {
import TheShapelessWay._
import shapeless.HNil
val r = combineHLatest(Foo("Hi") :: Foo(2) :: HNil)
println(r) // Foo(("Hi", 2))
// now lets "blow the bloody doors off"
// we don't want an HList, we want some case class from the fields
case class Address(line1: String, country: String)
val genAddress = Generic[Address]
val addressFields = Foo("first line") :: Foo("UK") :: HNil
val intoAddress = combineToCC(addressFields, genAddress)
println(intoAddress) // Foo(Address(first line,UK))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment