Created
June 22, 2011 21:11
-
-
Save msiegenthaler/1041216 to your computer and use it in GitHub Desktop.
Union Type in Scala with some experimental functions on top of it (like toEither)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import annotation.implicitNotFound | |
package object union { | |
private type ¬[A] = A => Nothing | |
private type ¬¬[A] = ¬[¬[A]] | |
private type ∧[A, B] = A with B | |
private type ∨[A, B] = ¬[∧[¬[A], ¬[B]]] // since (A ∨ B) ⇔ ¬(¬A ∧ ¬B) | |
sealed trait UnionInstance[A, B, T, -From, +To] { | |
protected[this] val manifestA: Manifest[A] | |
protected[this] val manifestB: Manifest[B] | |
private def asA(v: T) = v match { | |
case v: A => v | |
} | |
private def asB(v: T) = v match { | |
case v: B => v | |
} | |
def fold[R](fa: A => R)(fb: B => R)(v: T) = { | |
v match { | |
case i: Int => | |
if (manifestA >:> Manifest.Int) fa(asA(v)) | |
else fb(asB(v)) | |
case s: AnyRef => | |
val manifestS = Manifest.singleType(s) | |
if (manifestA.erasure.isAssignableFrom(manifestS.erasure)) fa(asA(v)) | |
else fb(asB(v)) | |
} | |
} | |
object first { | |
def unapply(v: T) = fold[Option[A]](Some(_))(b => None)(v) | |
} | |
object second { | |
def unapply(v: T) = fold[Option[B]](a => None)(Some(_))(v) | |
} | |
val left = first | |
val right = second | |
def toEither(v: T): Either[A, B] = fold[Either[A, B]](Left(_))(Right(_))(v) | |
} | |
@implicitNotFound(msg = "${T} not either ${A} or ${B}") | |
implicit def unionInstance[T, I, A: Manifest, B: Manifest]: UnionInstance[A, B, T, I, I] = new UnionInstance[A, B, T, I, I]() { | |
override val manifestA = manifest[A] | |
override val manifestB = manifest[B] | |
} | |
/** | |
* Type T is union-type of A and B. | |
* Usage: | |
* def my[T](value: T)(implicit u: Union[T, Int, String]) | |
* | |
* Features with u: | |
* - value match { case u.first(v) => v } | |
* - u.fold(_.toString)(_)(value) | |
* - u.toEither(value) | |
*/ | |
type Union[T, A, B] = UnionInstance[A, B, T, ¬¬[T], ∨[A, B]] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment