Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Algebras implementation which isn't based on nested type hierarchy
import scala.language.reflectiveCalls
type Nullary[A] = Unit
type Unary[A] = A
type Binary[A] = (A, A)
trait Algebra {
type Set
type Operation[F[_]] = F[Set] => Set
type NullaryOperation = Operation[Nullary]
type UnaryOperation = Operation[Unary]
type BinaryOperation = Operation[Binary]
}
type AdditiveNeutral = Algebra { val zero: NullaryOperation }
type AdditiveInverse = Algebra { val minus: UnaryOperation }
type AdditiveSemigroup = Algebra { val add: BinaryOperation }
type AdditiveMonoid = AdditiveNeutral with AdditiveSemigroup
type AdditiveGroup = AdditiveMonoid with AdditiveInverse
type MultiplicativeNeutral = Algebra { val one: NullaryOperation }
type MultiplicativeInverse = Algebra { val inverse: UnaryOperation }
type MultiplicativeSemigroup = Algebra { val mul: BinaryOperation }
type MultiplicativeMonoid = MultiplicativeNeutral with MultiplicativeSemigroup
type MultiplicativeGroup = MultiplicativeMonoid with MultiplicativeInverse
type Ring = AdditiveGroup with MultiplicativeMonoid
type Field = Ring with MultiplicativeInverse
implicit class NumericOps[A](private val value: A) {
def +(another: A)(implicit alg: AdditiveSemigroup { type Set = A }): A = alg.add((value, another))
def *(another: A)(implicit alg: MultiplicativeSemigroup { type Set = A }): A = alg.mul((value, another))
def -(another: A)(implicit alg: AdditiveGroup { type Set = A }): A = alg.add((value, alg.minus(another)))
def /(another: A)(implicit alg: MultiplicativeGroup { type Set = A }): A = alg.mul((value, alg.inverse(another)))
}
def test[A](a1: A, a2: A)(implicit field: Field { type Set = A }) =
(a1 + a2) - (a1 * a2 / a2)
implicit object intField extends Algebra {
type Set = Int
val zero: NullaryOperation = _ => 0
val minus: UnaryOperation = x => -x
val add: BinaryOperation = { case (x, y) => x + y }
val one: NullaryOperation = _ => 1
val inverse: UnaryOperation = x => 1 / x
val mul: BinaryOperation = { case (x, y) => x * y }
}
println(test(10, 5))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment