如何测试 Peano 数
How to test Peano numbers
我正在学习课程 Functional Programming Principles in Scala on Coursera. There is an example of implementation of the Peano numbers 是这样的:
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)
}
}
我的问题是:应该如何实施单元测试以成功测试对 peano 数的 + 和 - 操作?
为了以防万一,您可以在这里找到 remaining unit tests。
查看您的测试,您似乎想要测试相等条件,您应该为此编写一个函数:
def eq(i: Nat, j: Nat): Boolean =
if (i.isZero | j.isZero)
i.isZero == j.isZero
else
eq(i.predecessor, j.predecessor)
通过调用 eq
替换您的 ===
和 ==
。您也可以考虑覆盖 equal 方法,而不是将其作为外部(测试)函数。
感谢 Cyrille Corpet 的提示,在我看来,使用 case class
和 "compares by structure, not by reference" 很优雅。现在所有单元测试都通过了,没有任何变化。
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
}
我正在学习课程 Functional Programming Principles in Scala on Coursera. There is an example of implementation of the Peano numbers 是这样的:
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)
}
}
我的问题是:应该如何实施单元测试以成功测试对 peano 数的 + 和 - 操作?
为了以防万一,您可以在这里找到 remaining unit tests。
查看您的测试,您似乎想要测试相等条件,您应该为此编写一个函数:
def eq(i: Nat, j: Nat): Boolean =
if (i.isZero | j.isZero)
i.isZero == j.isZero
else
eq(i.predecessor, j.predecessor)
通过调用 eq
替换您的 ===
和 ==
。您也可以考虑覆盖 equal 方法,而不是将其作为外部(测试)函数。
感谢 Cyrille Corpet 的提示,在我看来,使用 case class
和 "compares by structure, not by reference" 很优雅。现在所有单元测试都通过了,没有任何变化。
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
}