ScalaCheck生成BST

ScalaCheck生成BST,scala,binary-search-tree,scalacheck,Scala,Binary Search Tree,Scalacheck,我试图用ScalaCheck为BST创建一个Gen,但是当我调用.sample方法时,它给了我java.lang.NullPointerException。我错在哪里 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

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

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
封闭特征树
案例类节点(左:树,右:树,v:Int)扩展了树
案例对象叶扩展树
导入org.scalacheck_
进口发电机_
导入任意
案例类GenerateBST(){
def genValue(左:树,右:树):Gen[Int]=(左,右)匹配{
大小写(Node(,,min),Node(,,max))=>任意[Int]。例如(x=>x>min&&x任意[Int]。例如(x=>x>min)
大小写(叶,节点(u,u,max))=>任意[Int]。例如(x=>x任意[Int]
}
val genNode=for{

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

def genTree: Gen[Tree] = Gen.lzy(oneOf(const(Leaf), genNode))
作为一个不相关的补充说明,在生成器定义中使用
这类
通常只是最后的手段。这意味着
示例
通常会失败(大约有三分之一的时间是使用固定版本的代码),更重要的是,如果有一天你想创建任意函数,导致
,你会看到很多可怕的
org.scalacheck.Gen$retrievaleror:无法生成值
异常

在这种情况下,通过使用
Gen.chooseNum
并在左右两侧顺序错误时交换,您可以非常轻松地避免
这种情况:

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))
}

嗨,我怎么会有这个异常!在属性评估时引发异常。>异常:org.scalacheck.Gen$Choose$IllegalBoundsError:invalid bounds:low=1,high=-1 org.scalacheck.Gen$Choose$$anon$5.Choose(Gen.scala:383)org.scalacheck.Gen$Choose$$anon$5.Choose(Gen.scala:381)org.scalacheck.Gen$Choose$$anon$7.Choose(Gen.scala:423)org.scalacheck.Gen$.chooseNum(Gen.scala:822)$line6.$read$$iw$$iw$GenerateBST$.genValue(:21)我不明白为什么…你能帮我吗?哦,对了,如果它们是一样的,你就得碰一个(而不是交换)。我会马上更新答案。好的,范围问题已经解决。您可能仍然需要对深度进行某种检查,因为
genNode
可能会被重复调用(但这是您希望
这样的版本或我的版本都能做到的).好的,但这样我们并不总是创建正确的BST,因为当我们碰撞时,我们不会检查更改是否涉及正确的子项。如果正确的子项值比父项多一个,我们就没有BST。对吗?
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)