Skip to content

Instantly share code, notes, and snippets.

@jyrimatti
Created October 10, 2012 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jyrimatti/3868667 to your computer and use it in GitHub Desktop.
Save jyrimatti/3868667 to your computer and use it in GitHub Desktop.
"Alternative way" for https://class.coursera.org/progfun-2012-001/lecture/index Week 3 Rational definition
// These should already exist in a standard library or similar
trait Showable[T] {
val show: T => String
}
trait StandardShowables {
implicit object StringIsShowable extends Showable[String] {
val show = (a: String) => a
}
implicit object BooleanIsShowable extends Showable[Boolean] {
val show = (a: Boolean) => a.toString
}
// ... for other standard types
}
trait Semigroup[T] {
val mappend: T => T => T
}
trait SemigroupOps {
implicit def semigroupOps[T: Semigroup](a: T) = new {
val |+| = implicitly[Semigroup[T]].mappend(a)(_)
}
}
trait Negatable[T] {
val neg: T => T
}
trait NegatableOps {
implicit def negatableOps[T: Negatable](a: T) = new {
val unary_- = implicitly[Negatable[T]].neg(a)
}
}
trait Subtractable[T] {
val subtract: T => T => T
}
trait SubtractableOps {
import Prelude._
implicit def subtractableOps[T: Subtractable](a: T) = new {
val - = implicitly[Subtractable[T]].subtract(a)(_)
}
implicit def NegatableSemigroupIsSubtractable[T: Semigroup: Negatable] = new Subtractable[T] {
val subtract = (a: T) => (b: T) => a |+| -b
}
}
trait Equal[T] {
val eq: T => T => Boolean
}
trait EqualOps {
implicit def equalOps[T: Equal](a: T) = new {
val === = implicitly[Equal[T]].eq(a)(_)
val !== = (b: T) => ! implicitly[Equal[T]].eq(a)(b)
}
}
trait Ordered[T] extends Equal[T] {
val lt: T => T => Boolean
}
trait OrderedOps {
implicit def orderedOps[T: Ordered](a: T) = new {
private def o = implicitly[Ordered[T]]
val < = o.lt(a)(_)
val > = (b: T) => ! (o.lt(a)(b) || o.eq(a)(b))
val <= = (b: T) => o.lt(a)(b) || o.eq(a)(b)
val >= = (b: T) => ! o.lt(a)(b)
}
}
object Prelude extends StandardShowables with
SemigroupOps with
NegatableOps with
SubtractableOps with
EqualOps with
OrderedOps {
def max[T: Ordered](elems: T*): T = elems reduce { (a, b) => if (a < b) b else a }
// using custom print function so that we can enforce the parameters to only Showable
def printline[A: Showable](a: A) = println(implicitly[Showable[A]].show(a))
def printline[A: Showable, B: Showable](a: A, b: B) = {
print(implicitly[Showable[A]].show(a))
print(implicitly[Showable[B]].show(b))
println
}
}
// some common util methods, which also already exist somewhere
object SomeUtils {
val gcd: Int => Int => Int =
a => b => if (b == 0) a else gcd(b)(a % b)
}
// the Rational definition itself. Notice that we don't strictly need any CLASSES
trait Rational {
val numerator: Int
val denominator: Int
}
object Rational {
def apply(numer: Int, denom: Int): Rational = {
val g = SomeUtils.gcd(numer)(denom)
new Rational {
val numerator = numer / g
val denominator = denom / g
}
}
def apply(numer: Int): Rational = apply(numer, 1)
}
// Some further definitions for Rational. May exist in a completely separate library.
object SomeRationalUtils {
implicit object RationalIsShowable extends Showable[Rational] {
val show = (a: Rational) => a.numerator + "/" + a.denominator
}
implicit object RationalIsNegatable extends Negatable[Rational] {
val neg = (a: Rational) => Rational(-1*a.numerator, a.denominator)
}
implicit object RationalAddSemigroup extends Semigroup[Rational] {
val mappend = (a: Rational) => (b: Rational) => Rational(
a.numerator*b.denominator + b.numerator*a.denominator,
a.denominator*b.denominator)
}
implicit object RationalIsOrdered extends Ordered[Rational] {
val lt = (a: Rational) => (b: Rational) => a.numerator * b.denominator < b.numerator * a.denominator
val eq = (a: Rational) => (b: Rational) => a.numerator == b.numerator && a.denominator == b.denominator
}
}
object RationalTest {
import Prelude._
import SomeRationalUtils._
def main(args: Array[String]) {
val x = Rational(1, 3)
val y = Rational(5, 7)
val z = Rational(3, 2)
printline("x: ", x)
printline("y: ", y)
printline("z: ", z)
printline("x-y-z: ", x - y - z)
printline("y+y: ", y |+| y) // using |+| since Scala implicitly provides + for strings, which screws up everything...
printline("x<y: ", x < y)
printline("max(x,y): ", max(x,y))
printline("2: ", Rational(2))
// notice that we didn't need to define subtraction or maximum at all: they came for free!
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment