Как проверить числа Пеано

Я прохожу курс " Принципы функционального программирования" в 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, Вы можете также рассмотреть возможность переопределения метода равенства вместо использования его в качестве внешней (тестовой) функции.

Другие вопросы по тегам