Skip to content

Instantly share code, notes, and snippets.

@davegurnell
Created December 10, 2016 15:52
Show Gist options
  • Select an option

  • Save davegurnell/cb3c7deb27b588ad004d0013da675b3c to your computer and use it in GitHub Desktop.

Select an option

Save davegurnell/cb3c7deb27b588ad004d0013da675b3c to your computer and use it in GitHub Desktop.
shapeless getters
import shapeless._
import shapeless.labelled._
final case class Employee(
name : String,
number : Int,
manager : Boolean
)
final case class IceCream(
name : String,
numCherries : Int,
inCone : Boolean
)
trait Getter[A, B] {
def apply(value: A): B
}
trait MkGetter[A, N] {
type Out
def create: Getter[A, Out]
}
object MkGetter {
type Aux[A, N, B] = MkGetter[A, N] { type Out = B }
}
object Main extends Demo {
val employee = Employee("Bill", 1, true)
val iceCream = IceCream("Cornetto", 0, true)
def getter[A, B](func: A => B): Getter[A, B] =
new Getter[A, B] {
def apply(value: A): B =
func(value)
}
// implicit def hnilMkGetter[N, B]: MkGetter.Aux[HNil, N, B] =
// new MkGetter[HNil, N] {
// type Out = B
// def create: Getter[HNil, B] =
// getter(hnil => ???)
// }
implicit def foundMkGetter[K, H, T <: HList, N](
implicit
ev: K <:< N
): MkGetter.Aux[FieldType[K, H] :: T, N, H] =
new MkGetter[FieldType[K, H] :: T, N] {
type Out = H
def create: Getter[FieldType[K, H] :: T, H] =
getter { case h :: t => h }
}
implicit def notFoundMkGetter[K, H, T <: HList, N, B](
implicit
tailMkGetter: MkGetter.Aux[T, N, B]
): MkGetter.Aux[FieldType[K, H] :: T, N, B] = {
val tailGetter = tailMkGetter.create
new MkGetter[FieldType[K, H] :: T, N] {
type Out = B
def create: Getter[FieldType[K, H] :: T, B] =
getter { case h :: t => tailGetter(t) }
}
}
implicit def genericMkGetter[A, R, N, B](
implicit
gen: LabelledGeneric.Aux[A, R],
mkGetter: MkGetter.Aux[R, N, B]
): MkGetter.Aux[A, N, B] = {
val rGetter = mkGetter.create
new MkGetter[A, N] {
type Out = B
def create: Getter[A, B] =
getter(a => rGetter(gen.to(a)))
}
}
def getter[A](w: Witness)(
implicit
mkGetter: MkGetter[A, w.T]
): Getter[A, mkGetter.Out] =
mkGetter.create
val g1: Getter[Employee, String] = getter[Employee]('name)
val g2: Getter[Employee, Int] = getter[Employee]('number)
val g3: Getter[Employee, Boolean] = getter[Employee]('manager)
// val g4 = getter[Employee]('bob)
println(g1(employee))
println(g2(employee))
println(g3(employee))
// println(g4(employee))
// println(employee)
// println(iceCream)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment