Skip to content

Instantly share code, notes, and snippets.

@zobar
Last active December 28, 2015 01:29
Show Gist options
  • Save zobar/7420886 to your computer and use it in GitHub Desktop.
Save zobar/7420886 to your computer and use it in GitHub Desktop.
Dimensional analysis in Scala
/project
/target
package abelian
trait Operation[-A <: Element, -B <: Element, +C <: Element] extends ((A, B) => C)
object Operation {
def apply[A <: Element, B <: Element, C <: Element](operation: (A, B) => C): Operation[A, B, C] =
new Operation[A, B, C] { def apply(a: A, b: B): C = operation(a, b) }
implicit def `*_identity`[A <: NonIdentity] =
Operation[A, Identity.type, A]((a, b) => a)
implicit def `*_inverse`[A <: Element, B <: Element](implicit operation: Operation[A, B, *[A, B]]) =
Operation[A, B#Inverse, *[A, B#Inverse]]((a, b) => new *(a, b))
implicit def `*_myInverse`[A <: Element, B <: Element](implicit evidence: A =:= B#Inverse) =
Operation[A, B, Identity.type]((a, b) => Identity)
implicit def commutative[A <: Element, B <: Element, C <: Element](implicit operation: Operation[B, A, C]): Operation[A, B, C] =
Operation((a, b) => operation.apply(b, a))
}
trait Element {
type Inverse <: Element
def *[A <: Element, B <: Element](factor: A)(implicit operation: Operation[this.type, A, B]): B =
operation(this, factor)
val inverse: Inverse
}
object Identity extends Element {
type Inverse = Identity.type
val inverse = this
override def toString = "1"
}
trait NonIdentity extends Element
trait Basic extends NonIdentity {
basic =>
class Inverse private[Basic] extends NonIdentity {
type Inverse = basic.type
val inverse: Inverse = basic
override def toString = s"$basic-1"
}
protected[this] def *[A <: Element] =
Operation[this.type, A, *[this.type, A]]((a, b) => new *(this, b))
val inverse = new Inverse
}
class *[A <: Element, B <: Element](val a: A, val b: B) extends NonIdentity {
type Inverse = *[A#Inverse, B#Inverse]
lazy val inverse = ??? // a.Inverse * b.Inverse
override def toString = s"$a.$b"
}
scalacOptions ++= Seq("-feature")
scalaVersion := "2.10.3"
package dimension
import abelian.{Basic => Dimension}
object Length extends Dimension {
override def toString = "L"
implicit def `*_mass` = *[Mass.type]
implicit def `*_time` = *[Time.type]
}
object Mass extends Dimension {
override def toString = "M"
implicit def `*_time` = *[Time.type]
}
object Time extends Dimension {
override def toString = "T"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment