Skip to content

Instantly share code, notes, and snippets.

@bkyrlach
Created March 6, 2019 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bkyrlach/cf8ea12ded3c6fb07c14d9c00b33a818 to your computer and use it in GitHub Desktop.
Save bkyrlach/cf8ea12ded3c6fb07c14d9c00b33a818 to your computer and use it in GitHub Desktop.
import shapeless.{::, HList, HNil}
import io.estatico.newtype.macros.newtype
object Program {
type EntityState =
Map[EID,Name] ::
Map[EID,Might] ::
Map[EID,Magic] ::
Map[EID,Hp] ::
HNil
@newtype case class EID(toInt: Int)
@newtype case class Name(toStr: String)
@newtype case class Might(toInt: Int)
@newtype case class Magic(toInt: Int)
@newtype case class Hp(toInt: Int)
trait Setter[A,B,K] {
def set(k: K)(b: B)(a: A): A
}
implicit def mapSetter[A,K]: Setter[Map[K,A],A,K] = new Setter[Map[K,A],A,K] {
def set(k: K)(a: A)(m: Map[K,A]): Map[K,A] = m + (k -> a)
}
implicit def headSetter[H, T <: HList, K, A](implicit ev: Setter[H,A,K]): Setter[H :: T, A, K] = new Setter[H :: T, A, K] {
def set(k: K)(a: A)(xs: H :: T): H :: T = ev.set(k)(a)(xs.head) :: xs.tail
}
implicit def tailSetter[X, T <: HList, K, A](implicit ev: Setter[T,A,K]): Setter[X :: T, A, K] = new Setter[X :: T, A, K] {
def set(k: K)(a: A)(xs: X :: T): X :: T = xs.head :: ev.set(k)(a)(xs.tail)
}
def saveValue[A,K,H <: HList](k: K)(a: A)(xs: H)(implicit ev: Setter[H,A,K]): H = ev.set(k)(a)(xs)
trait Merger[A,B,K] {
def merge(k: K)(a: A)(b: B): B
}
implicit def nilMErger[I <: HList, K]: Merger[HNil,I,K] = new Merger[HNil, I, K] {
def merge(k: K)(h: HNil)(i: I): I = i
}
implicit def headMerger[H <: HList, I <: HList, X, K](implicit ev: Setter[I,X,K], ev2: Merger[H,I,K]): Merger[X :: H,I,K] = new Merger[X :: H,I,K] {
def merge(k: K)(h: X :: H)(i: I): I = ev2.merge(k)(h.tail)(saveValue(k)(h.head)(i))
}
def saveAll[H <: HList, I <: HList, K](k: K)(toSave: H)(model: I)(implicit ev: Merger[H,I,K]): I = ev.merge(k)(toSave)(model)
def main(args: Array[String]): Unit = {
val initial =
Map.empty[EID,Name] ::
Map.empty[EID,Might] ::
Map.empty[EID,Magic] ::
Map.empty[EID,Hp] ::
HNil
val result = saveValue(EID(1))(Name("Loreck"))(initial)
println(result)
val result2 = saveAll(EID(1))(Name("Loreck") :: Might(11) :: Magic(3) :: Hp(9) :: HNil)(initial)
println(result2)
// Not all need to be present
val result3 = saveAll(EID(1))(Name("Loreck") :: Might(11) :: Hp(9) :: HNil)(initial)
println(result3)
// Order doesn't matter
val result4 = saveAll(EID(1))(Hp(9) :: Might(11) :: Magic(3) :: HNil)(initial)
println(result4)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment