Forked from milessabin/gist:8f4498c057da9e376014
Last active
August 29, 2015 14:20
-
-
Save trygvea/838fe6fd8b38b059932f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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