首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ScalaCheck生成BST

ScalaCheck生成BST
EN

Stack Overflow用户
提问于 2019-03-01 22:34:13
回答 1查看 235关注 0票数 4

我试图用ScalaCheck为BST创建一个Gen,但是当我调用.sample方法时,它给我的是java.lang.NullPointerException。我哪里错了?

代码语言:javascript
复制
sealed trait Tree

case class Node(left: Tree, right: Tree, v: Int) extends Tree

case object Leaf extends Tree

import org.scalacheck._
import Gen._
import Arbitrary.arbitrary

case class GenerateBST() {

  def genValue(left: Tree, right: Tree): Gen[Int] = (left, right) match {
    case (Node(_, _, min), Node(_, _, max)) => arbitrary[Int].suchThat(x => x > min && x < max)
    case (Node(_, _, min), Leaf) => arbitrary[Int].suchThat(x => x > min)
    case (Leaf, Node(_, _, max)) => arbitrary[Int].suchThat(x => x < max)
    case (Leaf, Leaf) => arbitrary[Int]
  }


  val genNode = for {
    left <- genTree
    right <- genTree
    v <- genValue(left, right)
  } yield Node(left, right, v)

  def genTree: Gen[Tree] = oneOf(const(Leaf), genNode)
}

GenerateBST().genTree.sample
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-01 23:34:14

由于您为递归数据类型递归定义生成器的方式,您需要在顶部使用Gen.lzy

代码语言:javascript
复制
def genTree: Gen[Tree] = Gen.lzy(oneOf(const(Leaf), genNode))

作为一个不相关的附注,在生成器定义中使用suchThat通常只是最后的手段。这意味着sample经常会失败(使用固定版本的代码,大约有三分之一的时间),更重要的是,如果有一天您想要创建导致Tree的任意函数,您将看到许多可怕的org.scalacheck.Gen$RetrievalError: couldn't generate value异常。

在这种情况下,您可以通过使用Gen.chooseNum并交换左右两侧(如果它们的顺序不正确)来很容易地避免suchThat

代码语言:javascript
复制
sealed trait Tree
case class Node(left: Tree, right: Tree, v: Int) extends Tree
case object Leaf extends Tree

import org.scalacheck.{ Arbitrary, Gen }

object GenerateBST {
  def swapIfNeeded(l: Tree, r: Tree): (Tree, Tree) = (l, r) match {
    // If the two trees don't have space between them, we bump one and recheck:
    case (Node(_, _, x), n @ Node(_, _, y)) if math.abs(x - y) <= 1 =>
      swapIfNeeded(l, n.copy(v = y + 1))
    // If the values are in the wrong order, swap:
    case (Node(_, _, x), Node(_, _, y)) if x > y => (r, l)
    // Otherwise do nothing:
    case (_, _) => (l, r)
  }

  def genValue(left: Tree, right: Tree): Gen[Int] = (left, right) match {
    case (Node(_, _, min), Node(_, _, max)) => Gen.chooseNum(min + 1, max - 1)
    case (Node(_, _, min), Leaf) => Gen.chooseNum(min + 1, Int.MaxValue)
    case (Leaf, Node(_, _, max)) => Gen.chooseNum(Int.MinValue, max - 1)
    case (Leaf, Leaf) => Arbitrary.arbitrary[Int]
  }

  val genNode = for {
    l0 <- genTree
    r0 <- genTree
    (left, right) = swapIfNeeded(l0, r0)
    v <- genValue(left, right)
  } yield Node(left, right, v)

  def genTree: Gen[Tree] = Gen.lzy(Gen.oneOf(Gen.const(Leaf), genNode))
}

现在,您可以使用Arbitrary[Whatever => Tree],而不必担心生成器故障:

代码语言:javascript
复制
scala> implicit val arbTree: Arbitrary[Tree] = Arbitrary(GenerateBST.genTree)
arbTree: org.scalacheck.Arbitrary[Tree] = org.scalacheck.ArbitraryLowPriority$$anon$1@606abb0e

scala> val f = Arbitrary.arbitrary[Int => Tree].sample.get
f: Int => Tree = org.scalacheck.GenArities$$Lambda$7109/289518656@13eefeaf

scala> f(1)
res0: Tree = Leaf

scala> f(2)
res1: Tree = Node(Leaf,Leaf,-20313200)

scala> f(3)
res2: Tree = Leaf

scala> f(4)
res3: Tree = Node(Node(Leaf,Leaf,-850041807),Leaf,-1)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54946728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档