ScalaCheck: The Definitive Guide은 재귀 적 데이터 구조에 대한 생성자를 만드는 방법을 설명합니다. 상기 발전기재귀 데이터 구조 테스트
import org.scalacheck.Gen
import org.scalacheck.Gen.{oneOf, listOf, lzy}
def genTree[T](genT: Gen[T]): Gen[Tree[T]] = lzy {
oneOf(genLeaf(genT), genNode(genT))
}
def genLeaf[T](genT: Gen[T]): Gen[Leaf[T]] =
genT.map(Leaf(_))
def genNode[T](genT: Gen[T]): Gen[Node[T]] = for {
children <listOf(
genTree(genT))
} yield Node(children)
책 그것이 StackOverflowError
발생할 수 호출 보여
trait Tree[T] {
def size: Int
}
case class Leaf[T](item: T) extends Tree[T] {
def size = 1
}
case class Node[T] (children: List[Tree[T]]) extends Tree[T] {
def size = children.map(_.size).sum
}
다음에,이 Gen[Tree[A]]
코드이다 :
첫째, 데이터 구조 정의 :
scala> genIntTree.sample
res0: Option[Tree[Int]] = Some(Leaf(2147483648))
scala> genIntTree.sample
res1: Option[Tree[Int]] = Some(Leaf(0))
scala> genIntTree.sample
java.lang.StackOverflowError
at org.scalacheck.Gen$$anonfun$1$$anonfun$apply...
다음과 같이 주어진 경우 MyList
데이터 구조 :
sealed abstract class MyList[+A]
case class Cons[+A](elem: A, rest: MyList[A]) extends MyList[A]
case object Empty extends MyList[Nothing]
다음과 같은 생성기 :
def genList[A](gen: Gen[A]): Gen[MyList[A]] =
lzy { oneOf(genCons(gen), Gen.const(Empty)) }
def genCons[A](gen: Gen[A]): Gen[MyList[A]] = for {
list <- genList(gen)
a <- gen
} yield Cons(a, list)
나의 이해는 listOf
의 Gen[Tree[A]]
의 사용이 StackOverflowError
에 대한 책임이 있다는 것입니다.
그러나 Gen[MyList[A]]
코드의 생성자에서 StackOverflowError
이 가능합니까?
충분한 genList
이 충분히 반환되면 Cons
이 반환됩니다.하지만 확실하지 않습니다.
'문제는 실제로 oneOf()가 탐색 할 경로를 임의로 선택했다는 것입니다. ' 위의'Tree' 예제에서,'oneOf (gen1, gen2, ...)'는 varargs리스트에'gen * '을 매번 생성 할 것입니까? 그렇다면 무한 재귀가 발생합니까? –