Skip to content

Instantly share code, notes, and snippets.

@laughedelic
Created October 3, 2013 10:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save laughedelic/6808000 to your computer and use it in GitHub Desktop.
Save laughedelic/6808000 to your computer and use it in GitHub Desktop.
Constructing union type from an HList
trait UnionOf[L <: HList] {
type Mix
type Out = not[Mix]
type is[O] = UnionAux[L, O]
}
/* Implicits for constructing union: */
object UnionOf {
implicit val nil =
new UnionOf[HNil] { type Mix = not[Nothing] }
implicit def last[H, T <: HNil] =
new UnionOf[H :: T] { type Mix = not[H] }
implicit def cons[H, T <: HList : shapeless.IsHCons](implicit m: UnionOf[T]) =
new UnionOf[H :: T] { type Mix = not[H] with m.Mix }
}
/* Stupid but necessary auxiliary stuff: */
trait UnionAux[L <: HList, Out]
object UnionAux {
implicit def uhlist[L <: HList](implicit u: UnionOf[L]) = new UnionAux[L, u.Out] {}
}
// Convenient aliases that will be put in scope by the package object
trait UnionHList {
type not[A] = A => Nothing
type SubtypeOf[U] = { type is[T] = not[not[T]] <:< U }
}
@laughedelic
Copy link
Author

Simple example of usage:

trait [E, L <: HList]
object  {
  implicit def isin[L <: HList
    , U : UnionOf[L]#is
    , E : SubtypeOf[U]#is
    ] = new (EL) {}
}

implicitly[Int  ∈ (Int :: Char :: HNil)]
implicitly[Char ∈ (Int :: Char :: HNil)]

trait Foo
trait Boo extends Foo
implicitly[Boo ∈ (Int :: Foo :: Char :: HNil)]

/* Shouldn't compile: */
// implicitly[Boolean ∈ (Int :: Char :: String :: HNil)]
// implicitly[Nothing ∈ HNil]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment