Created
October 10, 2012 21:47
-
-
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
This file contains hidden or 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
// 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