Skip to content

Instantly share code, notes, and snippets.

@tonosaman
Forked from jorgeortiz85/FoldUnion.scala
Created June 4, 2012 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonosaman/2870846 to your computer and use it in GitHub Desktop.
Save tonosaman/2870846 to your computer and use it in GitHub Desktop.
Folding over Scala union types
type ¬[A] = A => Nothing
type ∨[T, U] = ¬[¬[T] with ¬[U]]
type ¬¬[A] = ¬[¬[A]]
type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) }
class FoldUnion[T](t: T) {
def boxClass(x: java.lang.Class[_]): java.lang.Class[_] = x.toString match {
case "byte" => manifest[java.lang.Byte].erasure
case "char" => manifest[java.lang.Character].erasure
case "short" => manifest[java.lang.Short].erasure
case "int" => manifest[java.lang.Integer].erasure
case "long" => manifest[java.lang.Long].erasure
case "float" => manifest[java.lang.Float].erasure
case "double" => manifest[java.lang.Double].erasure
case _ => x
}
def subtype(x: java.lang.Class[_], y: java.lang.Class[_]): Boolean = {
y.isAssignableFrom(x) || boxClass(y).isAssignableFrom(boxClass(x))
}
def foldUnion[A, B, S](f1: A => S, f2: B => S)(implicit ev: (¬¬[T] <:< (A ∨ B)), ma: ClassManifest[A], mb: ClassManifest[B]): S = t match {
case a if subtype(a.asInstanceOf[AnyRef].getClass, ma.erasure) => f1(a.asInstanceOf[A])
case b if subtype(b.asInstanceOf[AnyRef].getClass, mb.erasure) => f2(b.asInstanceOf[B])
}
}
implicit def FoldUnion[T](t: T): FoldUnion[T] = new FoldUnion(t)
def size[T : (Int |∨| String)#λ](t : T) = t.foldUnion((i: Int) => i, (_: String).length)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment