mitch
08/31/2020, 9:40 AMvalue(rs: RandomSource): Sample<A>
). now alot of the code is currently using values (it shows the strikethrough in intellij) and I'm fixing those as well. I realized that there's a fair few functions like this one arb(...)
that wants Sequence in it, how would I go about that?sam
09/01/2020, 8:54 AMarb { n }
sam
09/01/2020, 8:58 AMfun Arb.Companion.from(f: () -> T): Arb<T>
sam
09/01/2020, 8:59 AMmitch
09/01/2020, 9:14 AMArb.create
already exist with the correct types, so i wonder if I can just add several more createsmitch
09/01/2020, 9:15 AMmitch
09/01/2020, 9:36 AMArb.choose(vararg pairs: Pair<Int, Arb<A>>)
in kotest
https://github.com/typelevel/scalacheck/blob/master/src/main/scala/org/scalacheck/Gen.scala#L1224-L1232mitch
09/01/2020, 9:38 AMsam
09/01/2020, 9:40 AMsam
09/01/2020, 9:41 AMsam
09/01/2020, 9:41 AMmitch
09/01/2020, 9:44 AM[1,2,3]
['a', 'b', 'c']
[]
-> yields []
sam
09/01/2020, 9:44 AMsam
09/01/2020, 9:45 AMmitch
09/01/2020, 9:46 AMArb.choose
would work. as in, when you do a bind, you'd assign something like weight 1 to the edge cases, and weight 9 to the randomized valuesmitch
09/01/2020, 9:47 AMsam
09/01/2020, 9:48 AMsam
09/01/2020, 9:50 AMsam
09/01/2020, 9:50 AMsam
09/01/2020, 9:51 AMsam
09/01/2020, 9:51 AM[1,2,3]
['a', 'b', 'c']
[] -> we treat this as [random]
sam
09/01/2020, 9:52 AMmitch
09/01/2020, 9:53 AMsam
09/01/2020, 9:53 AMsam
09/01/2020, 9:54 AMmitch
09/01/2020, 9:58 AMmitch
09/01/2020, 9:58 AMsam
09/01/2020, 10:02 AMmitch
09/01/2020, 10:03 AMvalue(rs)
i supposesam
09/01/2020, 10:03 AMsam
09/01/2020, 10:04 AMmitch
09/01/2020, 10:04 AMsam
09/01/2020, 10:04 AMsam
09/01/2020, 10:05 AMComposedArb
that has extra method(s) for dealing with this kind of thing.sam
09/01/2020, 10:06 AMsam
09/01/2020, 10:07 AMmitch
09/01/2020, 10:11 AMsam
09/01/2020, 10:12 AMmitch
09/01/2020, 10:12 AMedgecases(): Exhaustive<A>
(conceptually)sam
09/01/2020, 10:13 AMmitch
09/01/2020, 10:14 AMmitch
09/01/2020, 10:14 AMsam
09/01/2020, 10:15 AMsam
09/01/2020, 10:16 AMabstract class ComposedArb<out A> : Gen<A> {
fun edgecases(rs: RandomSource): List<A>
abstract fun value(rs: RandomSource): Sample<A>
}
sam
09/01/2020, 10:16 AMmitch
09/01/2020, 10:17 AMsam
09/01/2020, 10:17 AMmitch
09/01/2020, 10:18 AM(RandomSource) -> List<A>
kleisli?sam
09/01/2020, 10:18 AMsealed class Edgecases<out A> {
abstract fun values(rs: RandomSource): List<A>
class Static(val values: List<A>) : Edgecases<A> {
override fun values(rs: RandomSource): List<A> = values
}
class Dynamic(val fn: (RandomSource) -> List<A>) : Edgecases<A> {
override fun values(rs: RandomSource): List<A> = fn(rs)
}
}
sam
09/01/2020, 10:18 AMmitch
09/01/2020, 10:19 AMsam
09/01/2020, 10:19 AMsam
09/01/2020, 10:20 AMfun edges() :EdgeCases<A>
mitch
09/01/2020, 10:21 AM_ -> List<A>
sam
09/01/2020, 10:21 AMabstract class Arb<out A> : Gen<A>() {
abstract fun edges(): Edgecases<A> = Edgecases.Static(edgecases())
abstract fun edgecases(): List<A>
abstract fun values(rs: RandomSource): Sequence<Sample<A>>
companion object
}
sam
09/01/2020, 10:22 AMmitch
09/01/2020, 10:22 AMsam
09/01/2020, 10:23 AMmitch
09/01/2020, 10:23 AMusers who spent the time converting from 3.x to 4.xi can relate lol
sam
09/01/2020, 10:23 AMsam
09/01/2020, 10:23 AMsam
09/01/2020, 10:24 AMtypealias Edgecases = (RandomSource) -> List<A>
mitch
09/01/2020, 10:27 AMdata class Edgecases<A>(edges: (RandomSource) -> List<A>)
i'll get something ready,sam
09/01/2020, 10:27 AMsam
09/01/2020, 10:28 AMsam
09/01/2020, 10:29 AMsealed class Edgecases<out A> {
abstract fun values(rs: RandomSource): List<A>
class List(val values: List<A>) : Edgecases<A> {
override fun values(rs: RandomSource): List<A> = values
}
class Randomized(val fn: (RandomSource) -> List<A>) : Edgecases<A> {
override fun values(rs: RandomSource): List<A> = fn(rs)
}
}
mitch
09/01/2020, 10:32 AMSample<A>
and in this case Edgecases<A>
makes it easier to enrich and refactor in the future.sam
09/01/2020, 10:34 AMmitch
09/01/2020, 10:34 AMmitch
09/04/2020, 11:23 AMmitch
09/04/2020, 11:26 AMEdgecases<A>
yet)mitch
09/06/2020, 6:28 AMEdgecases<A>
i'm not entirely convinced with the cartesian product approach, as the size of minimum iterations can explode with the number of edgecase combinations. i.e.
a - [1, 2, 3]
b - [1, 2, 3, 4]
c - [1, 2]
d - [1, 2, 3, 4, 5]
e - [] - randomize 1 element
if we were to compute the product we'll end up with 3 * 4 * 2 * 5 * 1 = 120 minimum iterations.
currently Kotest takes the edgecases linearly due to generate(rs) and iterator.mitch
09/06/2020, 6:31 AM(a, b, c, d, e)
(1, 1, 1, 1, r)
(2, 2, 2, 2, r)
(3, 3, r, 3, r)
(r, 4, r, 4, r)
(r, r, r, 5, r)
mitch
09/06/2020, 6:40 AMDo you mean because of how to handle edgecases? If so, I would just ignore edge cases. They don't really make much sense once you get into compositionquestioning what's the correct thing to do in
bind
and flatMap
case..mitch
09/06/2020, 6:57 AMsam
09/06/2020, 5:03 PMsam
09/06/2020, 5:05 PMsam
09/06/2020, 5:06 PMsam
09/06/2020, 5:09 PMsam
09/06/2020, 5:10 PMsam
09/06/2020, 5:10 PMArb.randomOnly()
which returns a copy of the arb but with the edge cases removed (that randomOnly name is a bit lame though) and Arb.withEdgeCases to copy the arb with differnt edge cases.sam
09/06/2020, 5:11 PMmitch
09/07/2020, 12:34 AMfun generate(rs: RandomSource, edgesSamplingMode: Edgecases.SamplingMode = Edecases.SamplingMode.Exhaustive) = // implementation detail
// i'm making stuff up here
sealed class SamplingMode {
object Exhaustive : SamplingMode() // all exhaustive permutations
// if we want to dirty our generated distribution with edgecases with fixed probability
case class FixedProbabilitySampling(val samplingProbability: Double = 0.1) : SamplingMode()
// if we want more control over the ratio of the distribution
case class DynamicProbabilitySampling(val startProbability: Double = 1.0, val targetProbability = 0.1, val decayFunction: (previousProbability: Double, iterations: Int) -> Double) : SamplingMode()
}
mitch
09/07/2020, 12:40 AM(a, b, c, d, e)
(1, r, 1, 3, r)
(2, 2, 3, 2, r)
(3, 1, r, r, r)
(r, 4, 3, 1, r)
(r, 3, r, 5, r)
It's not as powerful as the exhaustive combinations, because it gives only an approximation of it. If things fail, dev will be presented with the random seed which they can use. I won't be surprised if this is a nice compromise for a system with many inputs.sam
09/07/2020, 12:55 AMmitch
09/07/2020, 3:32 AMAn interesting function to add would bewhich returns a copy of the arb but with the edge cases removed (that randomOnly name is a bit lame though) and Arb.withEdgeCases to copy the arb with differnt edge cases. (edited)Arb.randomOnly()
mitch
09/07/2020, 3:34 AMsam
09/07/2020, 4:07 AMsam
09/07/2020, 4:07 AMsam
09/07/2020, 4:07 AMmitch
09/07/2020, 8:00 AMmitch
09/07/2020, 8:02 AMmitch
09/07/2020, 8:04 AM