scalacheck:为无限流定义一个生成器,它依赖于前面的元素

时间:2018-03-25 01:23:16

标签: scalacheck property-testing

我正在尝试为Gen[Stream[A]] s的无限(懒惰评估)流定义A,其中每个元素A可以依赖于之前的元素。

作为最小的情况,我们可以使用Gen[Stream[Int]],其中下一个元素是前一个元素的+1+2。这里有一个haskell实现参考:

increasingInts :: Gen [Int]
increasingInts = arbitrary >>= go
  where
    go seed = do
      inc <- choose (1,2)
      let next = seed + inc
      rest <- go next
      return (next : rest)

我在Gen.sequence上尝试了Stream[Gen[A]],但得到了一个stackoverflow。我还尝试从头开始定义Gen,但gen的构造函数Gen是私有的,可以使用私有方法/类型。

此尝试还提供了stackoverflow。

  def go(seed: Int): Gen[Stream[Int]] =
    for {
      inc <- Gen.choose(1, 2)
      next = seed + inc
      rest <- Gen.lzy(go(next))
    } yield next #:: rest

  val increasingInts: Gen[Stream[Int]] = go(0)


increasingInts(Gen.Parameters.default, Seed.random()).get foreach println

所以我被困住了。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您可以通过以下方式实现您的目标:

val increasingInts = {
  val increments = Gen.choose(1, 2)
  val initialSeed = 0
  for {
    stream <- Gen.infiniteStream(increments)
  } yield stream.scanLeft(initialSeed)(_ + _)
}

.scanLeft.foldLeft类似,但会保留中间值,从而为您提供另一个Stream

我在这里写过scanLefthttps://www.scalawilliam.com/most-important-streaming-abstraction/