Type-level list of types with a bound

35 views
Skip to first unread message

Daniel Armak

unread,
May 19, 2015, 1:28:40 PM5/19/15
to scala-user

Hi,

I’ve been struggling with this, but I’m sure the type wizards here can solve this easily.

I can represent a list of types as a type, like this:

sealed trait TList

object TList {
  type TNil <: TList
  type :::[A, B <: TList] <: TList
}

How can I represent a list of subtypes of some Parent type, as a generic type?

This doesn’t work:

sealed trait TList[+T]

object TList {
  type TNil <: TList[Nothing]
  type :::[+A, B <: TList[A]] <: TList[A]
}

Scala doesn’t infer the LUB of the actual A and B type arguments to :::, it just complains that they’re not the same type:

trait Parent; trait A extends Parent; trait B extends Parent

def f[T <: TList[Parent]] = ()

f[A ::: B ::: TNil]

<console>:19: error: type arguments [A,TList.:::[B,TList.TNil]] do not conform to type :::'s type parameter bounds [+A,B <: TList[A]]

              f[A ::: B ::: TNil]

Thanks!

Daniel Armak

Matthew Pocock

unread,
May 21, 2015, 5:56:06 AM5/21/15
to Daniel Armak, scala-user
Hi Daniel,

I believe that you can do this and other related things with shapeless. It supports products and coproducts, and you can summon witnesses for things like LUBs.

https://github.com/milessabin/shapeless
https://gitter.im/milessabin/shapeless
https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0

In particular, see the .unify method on HList, and the implicit witness for this.

Matthew

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Dr Matthew Pocock
Turing ate my hamster LTD

Integrative Bioinformatics Group, School of Computing Science, Newcastle University

skype: matthew.pocock
tel: (0191) 2566550

Daniel Armak

unread,
May 21, 2015, 2:00:23 PM5/21/15
to Matthew Pocock, scala-user

Hi Matthew,

HList.unify operates on HList values, not on pure types. The LUB witness types also have value-level implicit constructors.

I wanted to make a type-level list of types in order to pass types as arguments to a macro, where values are inconvenient to pass (if the value is defined in a separate compilation unit from the macro invocation). I’ve since solved that need in a different way, but I’m still interested in making a generic type-level list of types.

Having seen the shapless LUB witness, I can write this:

sealed trait TList

object TList {
  type TNil <: TList
  type :::[+A, B <: TList] <: TList
}

sealed trait LubWitness[T <: TList, A]

object LubWitness {
  import TList._

  type LNil[T] = LubWitness[TNil, T]
  type LCons[A, B <: TList, T, Witness <: LubWitness[B, T], <:<[A, T]] <: LubWitness[A ::: B, T]
}

But the witness would have to be constructed and provided manually, because there’s no equivalent to implicit types, I guess.

So instead of this approach, I should emulate shapeless by writing traits (not abstract types) that would let the user construct (empty) instances witnessing the types and with appropriate implicit constructors.

This helps a lot. Thanks!

Daniel Armak


Daniel Armak
Reply all
Reply to author
Forward
0 new messages