Skip to content

Instantly share code, notes, and snippets.

@erikerlandson
Created August 26, 2015 14:44
Show Gist options
  • Save erikerlandson/6c40f53eb76c6fc5e749 to your computer and use it in GitHub Desktop.
Save erikerlandson/6c40f53eb76c6fc5e749 to your computer and use it in GitHub Desktop.
Testing ability to constrain type variable bindings to emulate unit algebra
object commutative {
import scala.language.implicitConversions
sealed class =!=[A,B]
trait LowerPriorityImplicits {
implicit def equal[A]: =!=[A, A] = sys.error("should not be called")
}
object =!= extends LowerPriorityImplicits {
implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] =
if (same != null) sys.error("should not be called explicitly with same type")
else new =!=[A,B]
}
trait A
case object A extends A
trait B
case object B extends B
trait C
case object C extends C
case class UnitValue1[U1](value: Double) {
def +(that: UnitValue1[U1]) = UnitValue1[U1](this.value + that.value)
// sharing 0 terms
def *[U2](that: UnitValue1[U2]): UnitValue2[U1, U2] = {
implicitly[U2 =!= U1]
UnitValue2[U1, U2](this.value * that.value)
}
def *[U2, U3](that: UnitValue2[U2, U3]): UnitValue3[U1, U2, U3] = {
implicitly[U2 =!= U1]
implicitly[U3 =!= U1]
implicitly[U3 =!= U2]
UnitValue3[U1, U2, U3](this.value * that.value)
}
// sharing 1 term
def *(that: UnitValue1[U1]): UnitValue1[U1] = UnitValue1[U1](this.value * that.value)
def *[U2](that: UnitValue2[U1, U2]): UnitValue2[U1, U2] = {
implicitly[U2 =!= U1]
UnitValue2[U1, U2](this.value * that.value)
}
def *[U2, U3](that: UnitValue3[U1, U2, U3]): UnitValue3[U1, U2, U3] = {
implicitly[U2 =!= U1]
implicitly[U3 =!= U1]
implicitly[U3 =!= U2]
UnitValue3[U1, U2, U3](this.value * that.value)
}
}
case class UnitValue2[U1, U2](value: Double) {
implicitly[U1 =!= U2]
def +(that: UnitValue2[U1, U2]) = UnitValue2[U1, U2](this.value + that.value)
// sharing 0 terms
def *[U3](that: UnitValue1[U3]): UnitValue3[U1, U2, U3] = {
implicitly[U3 =!= U1]
implicitly[U3 =!= U2]
UnitValue3[U1, U2, U3](this.value * that.value)
}
// sharing 1 term
// Scala calls these duplicates, because it can't understand that U1 =!= U2.
def *(that: UnitValue1[U1]): UnitValue2[U1, U2] = {
UnitValue2[U1, U2](this.value * that.value)
}
def *(that: UnitValue1[U2]): UnitValue2[U1, U2] = {
UnitValue2[U1, U2](this.value * that.value)
}
// Scala calls these duplicates, because it can't understand that U1 =!= U2.
def *[U3](that: UnitValue2[U1, U3]): UnitValue3[U1, U2, U3] = {
implicitly[U3 =!= U1]
implicitly[U3 =!= U2]
UnitValue3[U1, U2, U3](this.value * that.value)
}
def *[U3](that: UnitValue2[U2, U3]): UnitValue3[U1, U2, U3] = {
implicitly[U3 =!= U1]
implicitly[U3 =!= U2]
UnitValue3[U1, U2, U3](this.value * that.value)
}
// sharing 2 terms
def *(that: UnitValue2[U1, U2]): UnitValue2[U1, U2] = UnitValue2[U1, U2](this.value * that.value)
}
object UnitValue2 {
implicit def uv2Reorder01[U2, U1](uv2: UnitValue2[U2, U1]) = UnitValue2[U1, U2](uv2.value)
}
case class UnitValue3[U1, U2, U3](value: Double) {
def +(that: UnitValue3[U1, U2, U3]) = UnitValue3[U1, U2, U3](this.value + that.value)
}
object UnitValue3 {
implicit def uv3Reorder01[U1, U3, U2](uv3: UnitValue3[U1, U3, U2]) =
UnitValue3[U1, U2, U3](uv3.value)
implicit def uv3Reorder02[U2, U1, U3](uv3: UnitValue3[U2, U1, U3]) =
UnitValue3[U1, U2, U3](uv3.value)
implicit def uv3Reorder03[U2, U3, U1](uv3: UnitValue3[U2, U3, U1]) =
UnitValue3[U1, U2, U3](uv3.value)
implicit def uv3Reorder04[U3, U1, U2](uv3: UnitValue3[U3, U1, U2]) =
UnitValue3[U1, U2, U3](uv3.value)
implicit def uv3Reorder05[U3, U2, U1](uv3: UnitValue3[U3, U2, U1]) =
UnitValue3[U1, U2, U3](uv3.value)
}
val uv1a = UnitValue1[A](2)
val uv1b = UnitValue1[B](3)
val uv1c = UnitValue1[C](4)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment