Как проверить числа Пеано
Я прохожу курс " Принципы функционального программирования" в Scala на Coursera. Вот пример реализации чисел Пеано, который выглядит так:
abstract class Nat {
def isZero: Boolean
def predecessor: Nat
def successor: Nat = new Succ(this)
def +(that: Nat): Nat
def -(that: Nat): Nat
}
object Zero extends Nat {
def isZero = true
def predecessor: Nat = throw new Error("0.predecessor")
def +(that: Nat): Nat = that
def -(that: Nat): Nat = if (that.isZero) this else throw new Error("negative number")
}
class Succ(n: Nat) extends Nat {
def isZero: Boolean = false
def predecessor: Nat = n
def +(that: Nat): Nat = new Succ(n + that)
def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor
}
Я написал пару юнит-тестов. Большая часть прохода, но следующие, написанные наивно, не соответствуют очевидным причинам (сравнение разных случаев):
trait Fixture {
val one = new Succ(Zero)
val two = new Succ(one)
}
test("successor of zero is one") {
new Fixture {
assert(Zero.successor == one)
}
}
test("successor of one is two") {
new Fixture {
assert(one.successor == two)
}
}
test("one plus zero is one") {
new Fixture {
assert((one + Zero) === one)
}
}
test("one plus one is two") {
new Fixture {
assert((one + one) === two)
}
}
Мой вопрос: как должен быть реализован модульный тест, который успешно тестирует + и - операции над числами Пеано?
На всякий случай, здесь вы можете найти оставшиеся юнит-тесты.
2 ответа
Благодаря подсказке от Cyrille Corpet, мне кажется, что это элегантно использовать case class
который "сравнивает по структуре, а не по ссылке". Все юнит-тесты сейчас проходят без изменений.
case class Succ(n: Nat) extends Nat {
def isZero: Boolean = false
def predecessor: Nat = n
def +(that: Nat): Nat = new Succ(n + that)
def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor
}
Глядя на ваши тесты, выясняется, что вы хотите проверить условия равенства, вы должны написать для этого функцию:
def eq(i: Nat, j: Nat): Boolean =
if (i.isZero | j.isZero)
i.isZero == j.isZero
else
eq(i.predecessor, j.predecessor)
Замена вашего ===
& ==
по телефону eq
, Вы можете также рассмотреть возможность переопределения метода равенства вместо использования его в качестве внешней (тестовой) функции.