Skip to content

Instantly share code, notes, and snippets.

@jorgeortiz85
Created June 9, 2011 17:11
Show Gist options
  • Save jorgeortiz85/1017197 to your computer and use it in GitHub Desktop.
Save jorgeortiz85/1017197 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)
@remeniuk
Copy link

remeniuk commented Jun 9, 2011

Beautiful! Union types should seriously be added to Predef.

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