简体   繁体   中英

Construct a type from HList of type classes

Given this code:

abstract class Col[A](val name: String)

case object Name extends Col[String]("name")
case object Age extends Col[Int]("age")

val cols = Name :: Age :: HNil

type TableDef = ??? // such that `type TableDef = String :: Int :: HNil`

How to derive TableDef in a generic way? I suspect it has to be a macro so that it can take arbitrary HList of Col[_] .

You can get most of the way there with shapeless.ops.Comapped ,

scala> import shapeless._, ops.hlist._
import shapeless._
import ops.hlist._

scala> Comapped[Col[String] :: Col[Int] :: HNil, Col]
res0: shapeless.ops.hlist.Comapped[shapeless.::[Col[String],shapeless.::[Col[Int],shapeless.HNil]],Col]{type Out = shapeless.::[String,shapeless.::[Int,shapeless.HNil]]} = shapeless.ops.hlist$Comapped$$anon$162@69bb4bc0

scala> type TableDef = res0.Out
defined type alias TableDef

scala> val foo: TableDef = "foo" :: 23 :: HNil
foo: TableDef = foo :: 23 :: HNil

scala> val foo: TableDef = "foo" :: true :: HNil
<console>:18: error: type mismatch;
 found   : shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]
 required: TableDef
    (which expands to)  shapeless.::[String,shapeless.::[Int,shapeless.HNil]]
       val foo: TableDef = "foo" :: true :: HNil
                                 ^

Note that this relies on the element types having Col as a direct outer type constructor. If you want to accommodate types like Name and Age which hide Col via a subtype then that would be possible via a variation on Comapped which takes subtypes into account.

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