Skip to content

Instantly share code, notes, and snippets.

@trygvea
Forked from milessabin/gist:8f4498c057da9e376014
Last active August 29, 2015 14:20
Show Gist options
  • Save trygvea/838fe6fd8b38b059932f to your computer and use it in GitHub Desktop.
Save trygvea/838fe6fd8b38b059932f to your computer and use it in GitHub Desktop.
package shapeless.examples
import shapeless._
import poly._
import labelled._
sealed trait Message
case class Ping(id: Long, sender: String) extends Message
case class Pong(id: Long, receiver: String) extends Message
case class Cookies(id: Long, message: Int) extends Message
sealed trait Tree[T]
case class Leaf[T](t: T) extends Tree[T]
case class Node[T](l: Tree[T], r: Tree[T]) extends Tree[T]
sealed trait MTree[T]
case class MLeaf[T](t: T) extends MTree[T]
case class MNode[T](ts: List[MTree[T]]) extends MTree[T]
trait UpdateField[T, E] {
def apply(t: T, f: E => E): T
}
object UpdateField extends UpdateField0 {
implicit def updateHNil[E]: UpdateField[HNil, E] =
new UpdateField[HNil, E] {
def apply(t: HNil, f: E => E): HNil = t
}
implicit def updateHCons[H, T <: HList, E]
(implicit
upHead: Lazy[UpdateField[H, E]],
upTail: Lazy[UpdateField[T, E]]
): UpdateField[H :: T, E] =
new UpdateField[H :: T, E] {
def apply(t: H :: T, f: E => E): H :: T = {
upHead.value(t.head, f) :: upTail.value(t.tail, f)
}
}
implicit def updateCNil[E]: UpdateField[CNil, E] =
new UpdateField[CNil, E] {
def apply(t: CNil, f: E => E): CNil = t
}
implicit def updateCCons[E, L, R <: Coproduct]
(implicit
upLeft: Lazy[UpdateField[L, E]],
upRight: Lazy[UpdateField[R, E]]
): UpdateField[L :+: R, E] =
new UpdateField[L :+: R, E] {
def apply(t: L :+: R, f: E => E): L :+: R = {
t match {
case Inl(l) => Inl(upLeft.value(l, f))
case Inr(r) => Inr(upRight.value(r, f))
}
}
}
implicit def updateElem[E]: UpdateField[E, E] =
new UpdateField[E, E] {
def apply(t: E, f: E => E) = f(t)
}
implicit def updateGen[T, E, R]
(implicit
gen: Generic.Aux[T, R],
upRepr: Lazy[UpdateField[R, E]]
): UpdateField[T, E] =
new UpdateField[T, E] {
def apply(t: T, f: E => E): T = {
gen.from(upRepr.value(gen.to(t), f))
}
}
}
trait UpdateField0 {
implicit def identityElem[T, E]: UpdateField[T, E] =
new UpdateField[T, E] {
def apply(t: T, f: E => E) = t
}
}
object UpdateExample extends App {
def updateField[T, E](t: T, f: E => E)
(implicit update: UpdateField[T, E]): T = update(t, f)
val msg: Message = Cookies(123, 12)
println(msg)
val res = updateField(msg, (l: Long) => l+1)
println(res)
val msg2: Message = Ping(123, "foo")
val res2 = updateField(msg2, (s: String) => s+"!!!")
println(res2)
val tree =
Node(
Node(
Leaf(1),
Leaf(2)
),
Leaf(3)
)
val res3 = updateField(tree, (i: Int) => i+1)
println(res3)
val tree2 =
MNode(
List(
MLeaf(1),
MNode(List(MLeaf(2), MLeaf(4), MLeaf(5))),
MLeaf(3)
)
)
val res4 = updateField(tree2, (i: Int) => i+1)
println(res4)
val l = List(Some(1), Some(2), Some(3))
val res5 = updateField(l, (i: Int) => i+1)
println(res5)
object plusOne extends (Int -> Int)(_ + 1)
val res6 = everywhere(plusOne)(tree)
println(res6)
}
trait Show[T] {
def show(t: T): String
}
trait Labelling[K] {
val label: String
}
object Labelling {
implicit def upperLabelling[T <: Symbol]
(implicit wT: Witness.Aux[T]): Labelling[T] =
new Labelling[T] {
val label = wT.value.name.toUpperCase
}
}
object Show {
implicit def intShow: Show[Int] =
new Show[Int] {
def show(t: Int) = t.toString
}
implicit def longShow: Show[Long] =
new Show[Long] {
def show(t: Long) = t.toString
}
implicit def stringShow: Show[String] =
new Show[String] {
def show(t: String) = t
}
implicit def boolShow: Show[Boolean] =
new Show[Boolean] {
def show(t: Boolean) = t.toString
}
implicit def hnilShow: Show[HNil] =
new Show[HNil] {
def show(t: HNil) = ""
}
implicit def fieldShow[K, V]
(implicit
labelling: Labelling[K],
valueShow: Lazy[Show[V]]
): Show[FieldType[K, V]] =
new Show[FieldType[K, V]] {
def show(t: FieldType[K, V]) =
labelling.label+": "+valueShow.value.show(t: V)
}
implicit def hconsShow[K, V, T <: HList]
(implicit
sh: Lazy[Show[FieldType[K, V]]],
st: Lazy[Show[T]]
): Show[FieldType[K, V] :: T] =
new Show[FieldType[K, V] :: T] {
def show(t: FieldType[K, V] :: T) =
"("+sh.value.show(t.head)+", "+st.value.show(t.tail)+")"
}
implicit def cnilShow: Show[CNil] =
new Show[CNil] {
def show(t: CNil) = ""
}
implicit def cconsShow[K, V, R <: Coproduct]
(implicit
sl: Lazy[Show[FieldType[K, V]]],
sr: Lazy[Show[R]]
): Show[FieldType[K, V] :+: R] =
new Show[FieldType[K, V] :+: R] {
def show(t: FieldType[K, V] :+: R) =
t match {
case Inl(kv) => "Inl("+sl.value.show(kv)+")"
case Inr(r) => "Inr("+sr.value.show(r)+")"
}
}
implicit def genShow[T, R]
(implicit
gen: LabelledGeneric.Aux[T, R],
repShow: Lazy[Show[R]]
): Show[T] =
new Show[T] {
def show(t: T) = repShow.value.show(gen.to(t))
}
}
object ShowExamples extends App {
def show[T](t: T)(implicit st: Show[T]): String = st.show(t)
implicit def showPong: Show[Pong] =
new Show[Pong] {
def show(t: Pong) = "!!! PONG !!!"
}
val msg: Message = Cookies(123, 12)
println(show(msg))
val pMsg: Message = Pong(45, "pong")
println(show(pMsg))
val tree =
Node(
Node(
Leaf(1),
Leaf(2)
),
Leaf(3)
)
println(show(tree))
}
object frob extends Poly1 {
implicit def caseInt = at[Int](_.toString)
implicit def caseString = at[String](_.length)
implicit def caseBoolean = at[Boolean](!_)
}
object headOption extends (List ~> Option) {
def apply[T](l: List[T]): Option[T] = l.headOption
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment