Reputation: 169
I would like to do some type level programming. Scala type macros are dead, and it seems that shapeless is unable to do what I want. All my problems would be resolve if I can get the following code to work (this code is borrowed from http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/ and http://michid.wordpress.com/2010/06/18/type-level-programming-equality/) It shows the implementation of a HList that has a "type remove" operator. The bug come from the "EQ" structure that test wether two type are equivalent in order to remove then or not. It seems to always return false in my case. I think that it's because I'm using "aliases" (?) but i do not see how to overcome this difficulty.
class Root {
def typed[T](t: => T) {}
}
trait BooleanCompute extends Root {
trait BOOL {
type OUT <: BOOL
type SELECT[TrueAction <: Action, FalseAction <: Action, Action] <: Action
}
case class TRUE() extends BOOL {
type OUT = TRUE
type SELECT[TrueAction <: Action, FalseAction <: Action, Action] = TrueAction
}
case class FALSE() extends BOOL {
type OUT = FALSE
type SELECT[TrueAction <: Action, FalseAction <: Action, Action] = FalseAction
}
}
object BooleanCompute extends BooleanCompute
import BooleanCompute._
case class Equality[A]() {
def check(x: A)(implicit t: TRUE) = t
def check[B](x: B)(implicit f: FALSE) = f
}
object Equality {
def witness[T] = null.asInstanceOf[T]
implicit val t: TRUE = null
implicit val f: FALSE = null
}
trait EQ[A, B] extends {
import Equality._
type OUT = out.type
val out = Equality[A]() check witness[B]
val test1 = Equality[List[Boolean]] check witness[List[Boolean]]
implicitly[test1.OUT =:= TRUE]
// Does not compile since tt is True
//implicitly[test1.t =:= FALSE]
val test2 = Equality[Nothing] check witness[AnyRef]
// Does not compile since ft is False
// implicitly[test2.t =:= TRUE]
implicitly[test2.OUT =:= FALSE]
}
object HList extends Root {
type :+:[H, T <: HList] = HCons[H, T]
val :+: = HCons
sealed trait HList {
self: HList =>
type SELECT[ConsAction <: Action, NilAction <: Action, Action] <: Action
type Remove[A] <: HList
}
final case class HCons[Head, Tail <: HList](head: Head, tail: Tail) extends HList {
self: HList =>
type SELECT[ConsAction <: Action, NilAction <: Action, Action] = ConsAction
type Remove[A] = SELECT[
EQ[Head, A]#OUT#SELECT[Tail#Remove[A], Head :+: Tail#Remove[A], HList],
HNil,
HList]
def :+:[T](v: T) = HCons(v, this)
}
sealed case class HNil() extends HList {
type SELECT[ConsAction <: Action, NilAction <: Action, Action] = NilAction
type Remove[A] = HNil
def :+:[T](v: T) = HCons(v, this)
}
}
object yo extends App {
import HList._
case class AA()
case class BB()
case class CC()
case class DD()
type YO = AA :+: BB :+:CC :+: HNil
type YoRemoved = AA :+: CC :+: HNil
val a = AA() :+: CC() :+: HNil()
typed[YoRemoved](a)
typed[YO#Remove[BB]](a)
}
Upvotes: 1
Views: 827
Reputation: 23046
What's the issue you're having with shapeless? The following works perfectly well,
scala> val yo = AA() :: BB() :: CC() :: HNil
yo: AA :: BB :: CC :: HNil = AA() :: BB() :: CC() :: HNil
scala> typed[YO](yo) // Compiles
scala> val yoRemoved = yo.filterNot[BB]
yoRemoved: AA :: CC :: HNil = AA() :: CC() :: HNil
scala> typed[YoRemoved](yoRemoved) // Compiles
Upvotes: 1