简体   繁体   中英

Create HMap from HList type

Given a type parameter that is an HList, I want to create a HMap with the typeTags of the HList's types as keys, like this:

(doesn't have to be a typeTag, just something that can hold the type)

def createMap[L <: HList](valueFunction:...):HMap = {
  //create an HMap with typeTags of HList elements as keys
  //values of HMap is created with passed 'valueFunction' which is a type parameterized function creating the value.
}

case class Person(..)
case class Address(..)

def valueFunction[T] = Map[Long, T]()

val hmap = createMap[Person :: Address :: HNil](valueFunction _)

val personValue:Map[Long, Person] = hmap(typeTag[Person])
  1. How can I implement createMap (signatures, return value and implementaion)?
  2. How can I specify a valid valueFunction?

I managed to do this with a bit of reflection. Should probably convert some of this to macros.

    import Repository._
    import shapeless.{HList, HMap, Id}

    import scala.collection.mutable
    import scala.reflect.api
    import scala.reflect.runtime.universe._

    trait Repository[L <: HList] {
      implicit val ltag: TypeTag[L]

      implicit object TLM extends (~??>[TypeTag, Long, mutable.Map])

      val repos: HMap[(~??>[TypeTag, Long, mutable.Map])#λ] = {
        val tts: List[TypeTag[_]] = ltag.tpe.dealias.typeArgs.dropRight(1).map(typeToTypeTag _)
        tts.tail.foldLeft(HMap[(~??>[TypeTag, Long, mutable.Map])#λ](getEntry(tts.head)))(_ + getEntry(_))
      }
    }

    object Repository {

      def getEntry[T](key: TypeTag[T]): (TypeTag[T], mutable.Map[Long, T]) = key -> mutable.Map[Long, T]()

      //copied and modified from shapeless ~?> in HMap
      class ~??>[K[_], K0, V[K0, _]] extends Serializable {
        class λ[K, V] extends Serializable
      }

      object ~??> extends NatTRel0 {
//not entirely sure if I need this method and/or the next one, but will keep it for now
        implicit def rel[K[_], K0, V[K0, _]]: ~??>[K, K0, V] = new (~??>[K, K0, V])

        implicit def idKeyWitness[K0, V[K0, _], T](implicit rel: ~??>[Id, K0, V]): rel.λ[T, V[K0, T]] = new rel.λ[Id[T], V[K0, T]]

        //this doesnt fit 3 type params, dont know how to port from ~?>
        //    implicit def idValueWitness[K[_], K0, T](implicit rel: ~??>[K, K0, Id]): rel.λ[K[T], T] = new rel.λ[K[T], Id[T]]
      }

      trait NatTRel0 {
        implicit def witness[K[_], K0, V[K0, _], T](implicit rel: ~??>[K, K0, V]): rel.λ[K[T], V[K0, T]] = new rel.λ[K[T], V[K0, T]]
      }

      def typeToTypeTag[T](tpe: Type)(implicit mirror: Mirror = runtimeMirror(getClass.getClassLoader)): TypeTag[T] =
        TypeTag(mirror, new api.TypeCreator {
          def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
            if (m eq mirror) tpe.asInstanceOf[U#Type]
            else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
        })
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM