Scala:验证正确性代码示例不起作用

时间:2018-03-01 09:13:00

标签: scala functional-programming substitution verification

我正在阅读Functional and Reactive Domain Modeling。在第1.5节第30页中,有一个例子:

credit(a, 100).flatMap(debit(_, 100))
=> Success(a.copy(balance = Balance(0 + 100))).flatMap(debit(_, 100))
=> debit(Account("a1", "John", .., Balance(100)), 100)
=> Success(a.copy(balance = Balance(100 - 100)))
=> Success(Account("a1", "John", .., Balance(0)))

我一般都理解,我们在这里做的是:我们用creditdebit操作替换函数及其实现。为了最终获得原始结果。但确切的例子不起作用。

例如,通过单元测试,我们使用断言来确保它有效。结果,为了验证代码,我可以编写表达式并进行比较。这是一个奇怪的语法。什么" =>"意思?没有任何比较。你如何验证正确性

以下是此验证之前的代码的完整示例,以便能够运行它:

import java.util.{ Date, Calendar }
import scala.util.{ Try, Success, Failure }
def today = Calendar.getInstance.getTime
type Amount = BigDecimal
case class Balance(amount: Amount = 0)
case class Account(no: String, name: String,
  dateOfOpening: Date, balance: Balance = Balance())

trait AccountService {
  def debit(a: Account, amount: Amount): Try[Account] = {
    if (a.balance.amount < amount)
      Failure(new Exception("Insufficient balance in account"))
    else Success(a.copy(balance = Balance(a.balance.amount – amount)))
  }
  def credit(a: Account, amount: Amount): Try[Account] =
    Success(a.copy(balance = Balance(a.balance.amount + amount)))
}

object AccountService extends AccountService
import AccountService._

val t = today
val a = Account("a1", "John", t)

1 个答案:

答案 0 :(得分:1)

您可能知道Scala中=>类型使用了FunctionA => BFunction[A, B]的别名。

但是在非Scala语境中,它有时会出现在例如在打印表达结果之前进行REPL。我想这正是我们在这里所拥有的,除了它还显示了部分结果(这本身很奇怪,因为我没有看到任何REPL这样做。)

credit(a, 100).flatMap(debit(_, 100))
=> Success(a.copy(balance = Balance(0 + 100))).flatMap(debit(_, 100))
   // credit substituted with its result
=> debit(Account("a1", "John", .., Balance(100)), 100)
=> Success(a.copy(balance = Balance(100 - 100)))
   // debit substitutes with its result
=> Success(Account("a1", "John", .., Balance(0)))
   // final result

对我而言,解释参考透明度和/或我们如何得出最终结果有点不一致/令人困惑的符号。

至于用断言测试结果,最后得到Try[Account]。即使没有任何测试框架匹配,您也可以将其检查为:

// given
val credit = credit(a, 100)

// when
val result = credit.flatMap(debit(_, 100))

// then
assert( result == Success(Account("a1", "John", .., Balance(0))) )

例如ScalaTest断言看起来像

result shouldBe Success(Account("a1", "John", .., Balance(0)))

虽然Specs2有更具体的东西

result must beSuccessfulTry.withValue( Account("a1", "John", .., Balance(0)) )

(他们都检查基本相同的东西,差异将是测试失败时的报告格式。)