Skip to content

Instantly share code, notes, and snippets.

@SystemFw
Created October 9, 2017 23:20
Show Gist options
  • Select an option

  • Save SystemFw/7995fd708898e1be51901c7af38853be to your computer and use it in GitHub Desktop.

Select an option

Save SystemFw/7995fd708898e1be51901c7af38853be to your computer and use it in GitHub Desktop.

Revisions

  1. SystemFw created this gist Oct 9, 2017.
    51 changes: 51 additions & 0 deletions Q.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@

    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))
    }
    }
    }
    }
    13 changes: 13 additions & 0 deletions Test.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    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
    }