gpt4 book ai didi

scala - 以模块化方式创建 Specs2 匹配器

转载 作者:行者123 更新时间:2023-12-04 07:27:37 27 4
gpt4 key购买 nike

我有函数A => Double .我想检查两个这样的函数对于给定的一组值是否给出相同的结果(最大容差,使用现有的 beCloseTo 匹配器)。
我希望能够写:

type TF = A => Double
(f: TF) must computeSameResultsAs(g: TF,tolerance: Double, tests: Set[A])
我想以模块化的方式构建这个匹配器,而不是简单地写一个 Matcher[TF]从头开始。
如果我能写的话可能会更好:
(f: TF) must computeSameResultsAs(g: TF)
.withTolerance(tolerance)
.onValues(tests: Set[A])
当匹配器失败时,我也想得到一个合理的描述。
编辑
在睡过它之后,我想出了以下内容。
def computeSameResultsAs[A](ref: A => Double, tolerance: Double, args: Set[A]): Matcher[A => Double] = 
args.map(beCloseOnArg(ref, tolerance, _)).reduce(_ and _)

def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg))
这比 Eric 的解决方案要短得多,但没有提供好的失败消息。我希望能够在第二种方法中重命名映射值。类似于以下内容(无法编译)。
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] = 
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg) aka "result on argument " + arg)

最佳答案

如果你想用第二个版本写东西,你需要创建一个新的 Matcher封装 beCloseTo 功能的类匹配器:

def computeSameResultsAs[A](g: A => Double, 
tolerance: Double = 0.0,
values: Seq[A] = Seq()) = TFMatcher(g, tolerance, values)

case class TFMatcher[A](g: A => Double,
tolerance: Double = 0.0,
values: Seq[A] = Seq()) extends Matcher[A => Double] {

def apply[S <: A => Double](f: Expectable[S]) = {
// see definition below
}

def withTolerance(t: Double) = TFMatcher(g, t, values)
def onValues(tests: A*) = TFMatcher(g, tolerance, tests)
}

此类允许使用您所追求的语法:
val f = (i: Int) => i.toDouble
val g = (i: Int) => i.toDouble + 0.1

"f must be close to another similar function with a tolerance" in {
f must computeSameResultsAs[Int](g).withTolerance(0.5).onValues(1, 2, 3)
}

现在,让我们看看如何重用 beCloseTo apply 中的匹配器方法:
def apply[S <: A => Double](f: Expectable[S]) = {
val res = ((v: A) => beCloseTo(g(v) +/- tolerance).apply(theValue(f.value(v)))).forall(values)

val message = "f is "+(if (res.isSuccess) "" else "not ")+
"close to g with a tolerance of "+tolerance+" "+
"on values "+values.mkString(",")+": "+res.message
result(res.isSuccess, message, message, f)
}

在上面的代码中,我们应用了一个返回 MatcherResult 的函数。 to a sequence of values :
((v: A) => beCloseTo(g(v) +/- tolerance).apply(theValue(f.value(v)))).forall(values)

注意:
  • fExpectable[A => Double]所以我们需要取它的实际value能够使用它
  • 同样,我们只能申请 Expectable[T]Matcher[T]所以我们需要使用方法theValue改造f.value(v)Expectable[Double] (来自 MustExpectations 特征)

  • 最后,我们何时得到 forall 的结果匹配,我们可以使用以下方法自定义结果消息:
  • 继承的result构建方法MatchResult (任何 applyMatcher 方法应该返回
  • 如果执行 beCloseTo,则传递一个 bool 值成功:.isSuccess
  • 根据 beCloseTo 的输入和结果消息传递格式良好的“ok”和“ko”消息匹配
  • 将它传递给 Expectable最初用于匹配:f ,因此最终结果的类型为 MatchResult[A => Double]

  • 我不确定根据您的要求我们可以得到多少模块化。在我看来,我们在这里能做的最好的事情就是重用 beCloseToforall .

    更新

    一个简短的答案可能是这样的:
    val f = (i: Int) => i.toDouble
    val g = (i: Int) => i.toDouble + 1.0

    "f must be close to another similar function with a tolerance" in {
    f must computeSameResultsAs[Int](g, tolerance = 0.5, values = Seq(1, 2, 3))
    }

    def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
    verifyFunction((a: A) => (beCloseTo(ref(a) +/- tolerance)).apply(theValue(f(a)))).forall(values)
    }

    上面的代码会创建一条失败消息,例如:
    In the sequence '1, 2, 3', the 1st element is failing: 1.0 is not close to 2.0 +/- 0.5

    这应该几乎可以开箱即用。缺少的部分是来自 A => MatchResult[_] 的隐式转换。至 Matcher[A] (我将添加到下一个版本):
    implicit def functionResultToMatcher[T](f: T => MatchResult[_]): Matcher[T] = (t: T) => {
    val result = f(t)
    (result.isSuccess, result.message)
    }

    您可以使用 foreach 而不是 forall如果你想得到所有的失败:
    1.0 is not close to 2.0 +/- 0.5; 2.0 is not close to 3.0 +/- 0.5; 3.0 is not close to 4.0 +/- 0.5

    更新 2

    这每天都变得更好。使用最新的 specs2 快照,您可以编写:
    def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
    ((a: A) => beCloseTo(ref(a) +/- tolerance) ^^ f).forall(values)
    }

    更新 3

    现在有了最新的 specs2 快照,您可以编写:
    def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
    ((a: A) => beCloseTo(ref(a) +/- tolerance) ^^ ((a1: A) => f(a) aka "the value")).forall(values)
    }

    失败消息将是:
    In the sequence '1, 2, 3', the 1st element is failing: the value '1.0' is not close to 2.0 +/- 0.5

    关于scala - 以模块化方式创建 Specs2 匹配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7916792/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com