Skip to content

Instantly share code, notes, and snippets.

@monadplus
Created May 9, 2019 06:50
Show Gist options
  • Save monadplus/88d7c73e1c81e12aee1f856312fa78b4 to your computer and use it in GitHub Desktop.
Save monadplus/88d7c73e1c81e12aee1f856312fa78b4 to your computer and use it in GitHub Desktop.
Last element of a product
import shapeless._
import scala.annotation.implicitNotFound
trait DeepFn1[T] {
type Out
def apply(t: T): Out
}
@implicitNotFound("Implicit not found: Last[${L}]. ${L} is empty, so there is no last element.")
trait Last[L] extends DeepFn1[L]
object Last extends LastSyntax {
def apply[L](implicit last: Last[L]): Aux[L, last.Out] = last
type Aux[L, Out0] = Last[L] {type Out = Out0}
implicit def hsingleLast[H]: Aux[H :: HNil, H] =
new Last[H :: HNil] {
type Out = H
def apply(h: H :: HNil): Out = h.head
}
implicit def hlistLast[H, T <: HList, OutT]
(implicit last: Last.Aux[T, OutT]): Aux[H :: T, OutT] =
new Last[H :: T] {
type Out = OutT
def apply(hlist: H :: T): Out = last(hlist.tail)
}
implicit def genericLast[In, Gen, OutT]
(implicit gen: Generic.Aux[In, Gen],
last: Last.Aux[Gen, OutT]): Last.Aux[In, OutT] =
new Last[In] {
type Out = OutT
def apply(in: In): OutT =
last(gen.to(in))
}
}
trait LastSyntax {
implicit def toLastOps[A](a: A)(implicit ev: Last[A]): LastOps[A, ev.Out] =
new LastOps[A, ev.Out] {
def last: ev.Out = ev(a)
}
sealed trait LastOps[A, Out] {
def last: Out
}
}
import Last._
case class Person(name: String, age: Int)
val john = Person("John", 25)
val age: Int = john.last // 25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment