diff options
author | odersky <odersky@gmail.com> | 2017-02-27 15:46:09 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-27 15:46:09 +0100 |
commit | 179a5d601575bc4f07239667cc1f3fa758f8e98d (patch) | |
tree | 37d8a695526f203651f8166f26073936d380f120 /tests/run | |
parent | 23ed45b64e0443d87c648bdd04038342a8528385 (diff) | |
parent | bee890af9c1105f8cb3558715d80f6212f4639c0 (diff) | |
download | dotty-179a5d601575bc4f07239667cc1f3fa758f8e98d.tar.gz dotty-179a5d601575bc4f07239667cc1f3fa758f8e98d.tar.bz2 dotty-179a5d601575bc4f07239667cc1f3fa758f8e98d.zip |
Merge pull request #2011 from dotty-staging/hmap-test
HMap test case
Diffstat (limited to 'tests/run')
-rw-r--r-- | tests/run/hmap.scala | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/tests/run/hmap.scala b/tests/run/hmap.scala new file mode 100644 index 000000000..d84419ce1 --- /dev/null +++ b/tests/run/hmap.scala @@ -0,0 +1,97 @@ +trait Tuple +case class TCons[H, T <: Tuple](h: H, t: T) extends Tuple +final case object TNil extends Tuple + +// Type level natural numbers ------------------------------------------------- + +sealed trait Nat +sealed trait Succ[P <: Nat] extends Nat +sealed trait Zero extends Nat + +// Accessor type class to compute the N'th element of an Tuple L -------------- + +trait At[L <: Tuple, N <: Nat, Out] { + def apply(l: L): Out +} + +object At { + implicit def caseZero[H, T <: Tuple]: At[H TCons T, Zero, H] = + new At[H TCons T, Zero, H] { + def apply(l: H TCons T): H = { + val (h TCons _) = l + h + } + } + + implicit def caseN[H, T <: Tuple, N <: Nat, O] + (implicit a: At[T, N, O]): At[H TCons T, Succ[N], O] = + new At[H TCons T, Succ[N], O] { + def apply(l: H TCons T): O = { + val (_ TCons t) = l + a(t) + } + } +} + +// An HMap is an Tuple with HEntry elements. We are reusing Tuple for it's nice syntax + +final case class HEntry[K, V](value: V) + +// Accessor type class to compute the element of type K in a HMap L ----------- + +trait PhantomGet[K, M <: Tuple, I <: Nat] // extends PhantomAny + +object PhantomGet { + implicit def getHead[K, V, T <: Tuple] + : PhantomGet[K, HEntry[K, V] TCons T, Zero] = null + + implicit def getTail[K, H, T <: Tuple, I <: Nat] + (implicit t: PhantomGet[K, T, I]) + : PhantomGet[K, H TCons T, Succ[I]] = null +} + +// Syntax --------------------------------------------------------------------- + +object syntax { + object hmap { + implicit class HmapGet[M <: Tuple](m: M) { + def get[K, V, I <: Nat](k: K) + (implicit + g: PhantomGet[k.type, M, I], + a: At[M, I, HEntry[k.type, V]] + ): V = a(m).value + } + + def --[K, V](key: K, value: V) = HEntry[key.type, V](value) + } +} + +object Test { + def main(args: Array[String]): Unit = { + import syntax.hmap._ + + val map1 = + TCons(HEntry[K = "name"]("foo"), + TCons(HEntry[K = "genre"](true), + TCons(HEntry[K = "moneyz"](123), + TCons(HEntry[K = "cat"]("bar"), + (TNil: TNil.type))))) + + assert(map1.get("name") == "foo") + assert(map1.get("genre") == true) + assert(map1.get("moneyz") == 123) + assert(map1.get("cat") == "bar") + + val map2 = + TCons(--("name" , "foo"), + TCons(--("genre" , true), + TCons(--("moneyz", 123), + TCons(--("cat" , "bar"), + TNil)))) + + assert(map2.get("name") == "foo") + assert(map2.get("genre") == true) + assert(map2.get("moneyz") == 123) + assert(map2.get("cat") == "bar") + } +} |