scalacheck:为无限流定义一个生成器,对先前的元素有一定的依赖性

scalacheck: define a generator for an infinite stream with some dependence on previous elements

我正在尝试为 A 的无限(延迟计算)流定义一个 Gen[Stream[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)

我已经在 Stream[Gen[A]] 上尝试了 Gen.sequence,但遇到了 Whosebug。我还尝试从头开始定义 Gen,但是 Gen 的构造函数 gen 是私有的,并且可以与私有 methods/types.

一起使用

这个尝试也给出了一个计算器。

  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

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

你想要的可以这样实现:

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

.scanLeft 就像一个 .foldLeft 但保留了中间值,因此给你另一个 Stream.


我在这里写了关于 scanLeft 的文章:https://www.scalawilliam.com/most-important-streaming-abstraction/