Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jackfarrington/d502d38bf3f8e28c601d to your computer and use it in GitHub Desktop.
Save jackfarrington/d502d38bf3f8e28c601d to your computer and use it in GitHub Desktop.
Scala By Example exercise 6.0.3
/*
* The trait Nat is provided by the text.
*/
trait Nat {
def isZero: Boolean
def predecessor: Nat
def successor: Nat
def +(that: Nat): Nat
def -(that: Nat): Nat
// toInt is added for demonstration only and is not required by the implementation.
def toInt: Int
}
/*
* The object Zero is provided by the text.
*/
object Zero extends Nat {
def isZero: Boolean = true
def predecessor: Nat = error("negative number")
def successor: Nat = new Succ(Zero)
def +(that: Nat): Nat = that
def -(that: Nat): Nat = if (that.isZero) Zero else error("negative number")
val toInt: Int = 0
}
/*
* The class Succ is provided by the text.
*/
class Succ(x: Nat) extends Nat {
def isZero: Boolean = false
def predecessor: Nat = x
def successor: Nat = new Succ(this)
def +(that: Nat): Nat = x + that.successor
def -(that: Nat): Nat = if (that.isZero) this else x - that.predecessor
val toInt: Int = x.toInt + 1
}
/*
* Exercise 6.0.3 Write an implementation Integer of integer numbers. The implementation
* should support all operations of class Nat while adding two methods:
*
* def isPositive: Boolean
* def negate: Integer
*
* The first method should return true if the number is positive. The second method
* should negate the number. Do not use any of Scala’s standard numeric classes in your
* implementation. (Hint: There are two possible ways to implement Integer. One can
* either make use the existing implementation of Nat, representing an integer as a
* natural number and a sign. Or one can generalize the given implementation of Nat to
* Integer, using the three subclasses Zero for 0, Succ for positive numbers and Pred
* for negative numbers.)
*/
/*
* Encapsulate the new sign behavior in a trait.
*/
trait Sign {
def isPositive: Boolean
def negate: Sign
}
/*
* Indicates a positive sign value.
*/
object Positive extends Sign {
def isPositive: Boolean = true
def negate: Sign = Negative
}
/*
* Indicates a negative sign value.
*/
object Negative extends Sign {
def isPositive: Boolean = false
def negate: Sign = Positive
}
/*
* The Integer class wraps a natural number and optionally may take a sign.
*/
case class Integer(value: Nat, sign: Sign = Positive) extends Nat with Sign {
def isZero: Boolean = value.isZero
def predecessor: Nat =
if (isZero) new Integer(value.successor, Negative)
else if (sign.isPositive) new Integer(value.predecessor, sign)
else new Integer(value.successor, Negative)
def successor: Nat =
if (isZero) new Integer(value.successor, Positive)
else if (sign.isPositive) new Integer(value.successor, sign)
else new Integer(value.predecessor, Negative)
def +(that: Nat): Nat =
if (isZero) that
else if (sign.isPositive) this.predecessor + that.successor
else this.successor + that.predecessor
def -(that: Nat): Nat =
if (that.isZero) this
else that match {
case Integer(v, s) => this + new Integer(v, s.negate)
}
def isPositive: Boolean = sign.isPositive
def negate: Integer = new Integer(value, sign.negate)
// The following two definitions are for demonstration only and are not required.
val toInt: Int = if (sign.isPositive) value.toInt else -value.toInt
override def toString =
"" + { if (this.isZero) "" else if (sign.isPositive) "+" else "-" } + value.toInt
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment