Skip to content

Instantly share code, notes, and snippets.

@SystemFw
Created October 9, 2017 23:20
Show Gist options
  • Save SystemFw/7995fd708898e1be51901c7af38853be to your computer and use it in GitHub Desktop.
Save SystemFw/7995fd708898e1be51901c7af38853be to your computer and use it in GitHub Desktop.
Shapeless: create an HList of functions from case class T to each of its fields
object Q {
import shapeless._, labelled._, ops.record.Selector
trait Accessors[T, I] {
type Out
def value: Out
}
object Accessors {
type Aux[T, I, O] = Accessors[T, I] { type Out = O }
class Curry[T] {
def get[L](implicit ev: LabelledGeneric.Aux[T, L],
a: Accessors[T, L]): a.Out =
a.value
}
def of[T] = new Curry[T]
def instance[T, I, O](body: O): Accessors.Aux[T, I, O] =
new Accessors[T, I] {
type Out = O
def value = body
}
implicit def hnil[T]: Accessors.Aux[T, HNil, HNil] = instance(HNil)
implicit def kv[T, K <: Symbol, V, R <: HList, R1 <: HList](
implicit accessor: Accessor[T, K],
next: Accessors.Aux[T, R, R1])
: Accessors.Aux[T, FieldType[K, V] :: R, (T => accessor.Out) :: R1] =
instance(accessor.get :: next.value)
trait Accessor[T, K] {
type Out
def get: T => Out
}
object Accessor {
type Aux[T, K, O] = Accessor[T, K] { type Out = O }
implicit def all[T, K <: Symbol, L <: HList, O](
implicit gen: LabelledGeneric.Aux[T, L],
select: Selector.Aux[L, K, O]): Accessor.Aux[T, K, O] =
new Accessor[T, K] {
type Out = O
def get: T => Out = t => select(gen.to(t))
}
}
}
}
object Test {
import shapeless._
import Q._
case class Foo(a: Int, b: String)
val foo = Foo(1, "yo")
def accessors = Accessors.of[Foo].get
val wellTypes: (Foo => Int) :: (Foo => String) :: HNil = accessors
val a = accessors.head.apply(foo) //1
val b = accessors.tail.head.apply(foo) //yo
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment