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/
我正在尝试为 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/