Skip to content

Instantly share code, notes, and snippets.

@netanelrabinowitz
Last active November 21, 2018 18:32
Show Gist options
  • Select an option

  • Save netanelrabinowitz/7b9619fa68a3ff0da2afbd35698f2b2e to your computer and use it in GitHub Desktop.

Select an option

Save netanelrabinowitz/7b9619fa68a3ff0da2afbd35698f2b2e to your computer and use it in GitHub Desktop.
/**
* User: netanelrabinowitz
* Date: 16/12/2017
* Time: 14:11
*/
import shapeless._
import shapeless.ops.hlist
import shapeless.labelled.{field, FieldType}
trait Default[A] {
def default: A
}
object Default {
def pure[A](empty: => A): Default[A] = {
new Default[A] {
override def default: A = empty
}
}
def apply[A](implicit default: Default[A]): Default[A] = default
implicit val intDefault: Default[Int] = pure(0)
implicit val doubleDefault: Default[Double] = pure(0.0)
implicit val strDefault: Default[String] = pure("")
implicit val booleanDefault: Default[Boolean] = pure(false)
implicit def optionDefault[A]: Default[Option[A]] = pure(None)
implicit def listDefault[A]: Default[List[A]] = pure(Nil)
implicit def mapDefault[K, V]: Default[Map[K, V]] = pure(Map.empty)
// product
implicit val hnilDefault: Default[HNil] =
pure(HNil)
implicit def hlistDefault[H, T <: HList](
implicit
hEncoder: Default[H],
tEncoder: Default[T]): Default[H :: T] = {
pure {
hEncoder.default :: tEncoder.default
}
}
implicit def genericDefault[A, R](
implicit
gen: Generic.Aux[A, R],
default: Default[R]): Default[A] = {
pure(gen.from(default.default))
}
}
trait Evo[A, B] {
def apply(a: A): B
}
object Evo {
// simpler version without the use of Diff and the ability to add new fields to newer versions
// implicit def genericEvolution[A, B, ARepr <: HList, BRepr <: HList, Unaligned <: HList](
// implicit
// aGen : LabelledGeneric.Aux[A, ARepr],
// bGen : LabelledGeneric.Aux[B, BRepr],
// inter : hlist.Intersection.Aux[ARepr, BRepr, Unaligned],
// align : hlist.Align[Unaligned, BRepr]
// ): Evo[A, B] = {
// new Evo[A, B] {
// def apply(a: A): B = bGen.from(align.apply(inter.apply(aGen.to(a))))
// }
// }
def pure[A](empty: => A): Default[A] =
new Default[A] {
def default: A = empty
}
implicit val hnilDefault: Default[HNil] =
pure[HNil](HNil)
implicit def hlistDefault[K <: Symbol, H, T <: HList](
implicit
hDefault: Lazy[Default[H]],
tDefault: Default[T]): Default[FieldType[K, H] :: T] =
pure(field[K](hDefault.value.default) :: tDefault.default)
implicit def genericEvolution[
A, B, ARepr <: HList, BRepr <: HList,
Common <: HList, Added <: HList, Unaligned <: HList](
implicit
aGen : LabelledGeneric.Aux[A, ARepr],
bGen : LabelledGeneric.Aux[B, BRepr],
inter : hlist.Intersection.Aux[ARepr, BRepr, Common],
diff : hlist.Diff.Aux[BRepr, Common, Added],
default : Default[Added],
prepend : hlist.Prepend.Aux[Added, Common, Unaligned],
align : hlist.Align[Unaligned, BRepr]
): Evo[A, B] = {
new Evo[A, B] {
def apply(a: A): B =
bGen.from(align(prepend(default.default, inter(aGen.to(a)))))
}
}
implicit class EvoOps[A](a: A) {
def to[B](implicit evolve: Evo[A, B]): B =
evolve.apply(a)
}
}
object Main {
import Evo._
case class V1(str: String, int: Int, bool: Boolean)
case class V2(bool: Boolean, str: String, double: Double)
def main(args: Array[String]): Unit = {
val v1 = V1("yolo", 3, true)
val v2 = v1.to[V2]
println(v2) // V2(true,yolo, 0.0)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment