scalacheck: определить генератор для бесконечного потока с некоторой зависимостью от предыдущих элементов

Я пытаюсь определить Gen[Stream[A]] для бесконечного (лениво оцененного) потока 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]] но получил переполнение стека. Я также попытался определить Gen с нуля, но конструктор gen за Gen является частным и работает с закрытыми методами / типами.

Эта попытка также дает переполнение стека.

  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 ответ

Решение

То, что вы хотите, может быть достигнуто с этим:

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/

Другие вопросы по тегам