scala> trait Assoc[K] { type V ; val value: V } defined trait Assoc scala> def mkAssoc[K, V0](k: K, v: V0): Assoc[k.type] { type V = V0 } = | new Assoc[k.type] { type V = V0 ; val value = v } mkAssoc: [K, V0](k: K, v: V0)Assoc[k.type]{type V = V0} scala> def lookup[K](k: K)(implicit assoc: Assoc[k.type]): assoc.V = assoc.value lookup: [K](k: K)(implicit assoc: Assoc[k.type])assoc.V scala> implicit def firstAssoc = mkAssoc(1, "Panda!") firstAssoc: Assoc[1.type]{type V = String} scala> implicit def secondAssoc = mkAssoc(2, 42) secondAssoc: Assoc[2.type]{type V = Int} scala> implicit def nameAssoc = mkAssoc("Name", "Mary") nameAssoc: Assoc["Name".type]{type V = String} scala> implicit def ageAssoc = mkAssoc("Age", 23) ageAssoc: Assoc["Age".type]{type V = Int} scala> lookup(1) res0: String = Panda! scala> lookup(2) res1: Int = 42 scala> lookup("Name") res2: String = Mary scala> lookup("Age") res3: Int = 23