Skip to content

Instantly share code, notes, and snippets.

@knutwalker
Created October 30, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knutwalker/da7da4262d1fc15a1ec4 to your computer and use it in GitHub Desktop.
Save knutwalker/da7da4262d1fc15a1ec4 to your computer and use it in GitHub Desktop.
import shapeless._
import shapeless.tag._
import shapeless.labelled._
import scala.annotation.implicitNotFound
object Pluck {
trait FindByName[L <: HList, K] extends DepFn1[L] {
type Out
}
object FindByName {
@implicitNotFound("${A} does not have a field ${K}.")
type PrettyAux[A, L <: HList, K, Out0] = FindByName[L, K] { type Out = Out0 }
type Aux[L <: HList, K, Out0] = FindByName[L, K] { type Out = Out0 }
def apply[L <: HList, K](implicit fbn: FindByName[L, K]): Aux[L, K, fbn.Out] = fbn
implicit def headByName[T <: HList, K, V]
: Aux[FieldType[K, V] :: T, K, V] =
new FindByName[FieldType[K, V] :: T, K] {
type Out = V
def apply(l: FieldType[K, V] :: T): Out = l.head
}
implicit def tailByName[H, T <: HList, K, V](implicit
fbn: FindByName[T, K])
: Aux[H :: T, K, fbn.Out] =
new FindByName[H :: T, K] {
type Out = fbn.Out
def apply(l: H :: T): Out = fbn(l.tail)
}
}
def pluck[A, T, R <: HList](col: List[A], item: String)(implicit
gen: LabelledGeneric.Aux[A, R],
bn: FindByName.PrettyAux[A, R, Symbol @@ item.type, T])
: List[T] = col.map(x ⇒ bn(gen.to(x)))
def test() = {
case class Foo(foo: String, bar: Int, baz: Boolean)
val xs = List(Foo("f", 42, true), Foo("g", 1337, false))
val foos: List[String] = pluck(xs, "foo")
val bars: List[Int] = pluck(xs, "bar")
val bazs: List[Boolean] = pluck(xs, "baz")
println(s"foos = ${foos}") // => foos = List(f, g)
println(s"bars = ${bars}") // => bars = List(42, 1337)
println(s"bazs = ${bazs}") // => bazs = List(true, false)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment