gpt4 book ai didi

scala - 高阶ScalaCheck

转载 作者:行者123 更新时间:2023-12-03 14:21:44 26 4
gpt4 key购买 nike

考虑以下类别定义:

trait Category[~>[_, _]] {
def id[A]: A ~> A
def compose[A, B, C](f: A ~> B)(g: B ~> C): A ~> C
}


这是一元函数的实例:

object Category {
implicit def fCat = new Category[Function1] {
def id[A] = identity
def compose[A, B, C](f: A => B)(g: B => C) = g.compose(f)
}
}


现在,类别受某些法律约束。相关组成( .)和标识( id):

forall f: categoryArrow -> id . f == f . id == f


我想用ScalaCheck进行测试。让我们尝试使用整数函数:

"Categories" should {
import Category._

val intG = { (_ : Int) - 5 }

"left identity" ! check {
forAll { (a: Int) => fCat.compose(fCat.id[Int])(intG)(a) == intG(a) }
}

"right identity" ! check {
forAll { (a: Int) => fCat.compose(intG)(fCat.id)(a) == intG(a) }
}
}


但是这些是通过(i)特定类型( Int)和(ii)特定函数( intG)量化的。所以这是我的问题:在概括上述测试方面我能走多远?或者换句话说,是否有可能创建任意 A => B函数的生成器,并将其提供给ScalaCheck?

最佳答案

我不完全了解希尔伯特的epsilon,我会采用更基本的方法,并使用ScalaCheck的ArbitraryGen选择要使用的函数。

首先,为要生成的函数定义一个基类。通常,可能会生成结果不确定的函数(例如被零除),因此我们将PartialFunction用作基类。

trait Fn[A, B] extends PartialFunction[A, B] {
def isDefinedAt(a: A) = true
}


现在,您可以提供一些实现。覆盖 toString,因此ScalaCheck的错误消息可理解。

object Identity extends Fn[Int, Int] {
def apply(a: Int) = a
override def toString = "a"
}
object Square extends Fn[Int, Int] {
def apply(a: Int) = a * a
override def toString = "a * a"
}
// etc.


我选择使用案例类从二进制函数生成一元函数,并将其他参数传递给构造函数。这不是唯一的方法,但我发现它是最简单的方法。

case class Summation(b: Int) extends Fn[Int, Int] {
def apply(a: Int) = a + b
override def toString = "a + %d".format(b)
}
case class Quotient(b: Int) extends Fn[Int, Int] {
def apply(a: Int) = a / b
override def isDefinedAt(a: Int) = b != 0
override def toString = "a / %d".format(b)
}
// etc.


现在,您需要创建 Fn[Int, Int]的生成器,并将其定义为隐式 Arbitrary[Fn[Int, Int]]。您可以一直添加生成器,直到脸色发青(多项式,由简单的函数组成复杂的函数等)。

val funcs = for {
b <- arbitrary[Int]
factory <- Gen.oneOf[Int => Fn[Int, Int]](
Summation(_), Difference(_), Product(_), Sum(_), Quotient(_),
InvDifference(_), InvQuotient(_), (_: Int) => Square, (_: Int) => Identity)
} yield factory(b)

implicit def arbFunc: Arbitrary[Fn[Int, Int]] = Arbitrary(funcs)


现在,您可以定义属性。使用 intG.isDefinedAt(a)避免产生不确定的结果。

property("left identity simple funcs") = forAll { (a: Int, intG: Fn[Int, Int]) =>
intG.isDefinedAt(a) ==> (fCat.compose(fCat.id[Int])(intG)(a) == intG(a))
}

property("right identity simple funcs") = forAll { (a: Int, intG: Fn[Int, Int]) =>
intG.isDefinedAt(a) ==> (fCat.compose(intG)(fCat.id)(a) == intG(a))
}


尽管我所展示的内容仅泛化了所测试的功能,但希望这能使您对如何使用高级类型系统技巧来泛化类型有所了解。

关于scala - 高阶ScalaCheck,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10518015/

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