Closed FintanH closed 4 years ago
@FintanH The combinator that I miss the most is frequency
, and here's an attempt in Rust using this crate. Hope it helps! Critiques are also welcome :)
use quickcheck::{Arbitrary, Gen};
pub type BoxedGenerator<G, T> = Box<dyn FnMut(&mut G) -> T>;
pub fn frequency<G, T>(g: &mut G, freqs: &mut [(i64, BoxedGenerator<G, T>)]) -> T
where
G: Gen,
{
if freqs.is_empty() {
panic!("frequency: received empty list")
}
if freqs.iter().all(|(v, _)| *v == 0) {
panic!("frequency: all weights were zero")
}
if freqs.iter().any(|(v, _)| *v < 0) {
panic!("frequency: some weight is negative")
}
let sum_of_weights: i64 = freqs.iter().map(|v| v.0).sum();
let mut weight = i64::arbitrary(g).abs() % sum_of_weights + 1;
// println!("s = {}, w = {}", sum_of_weights, weight);
for (v, f) in freqs {
if weight - *v <= 0 {
return f(g);
} else {
weight -= *v
};
}
panic!("did not exhaust weight {}", weight)
}
Thanks @hengchu :blush: I actually ended up experimenting with proptest
which allowed me to limit the search space a bit easier.
Regarding your code sample, you could bolster it up a bit you could use [NonEmpty](https://docs.rs/nonempty/0.1.5/nonempty/struct.NonEmpty.html)
instead of an array, that way you don't need to do the is_empty
check :)
Maybe something like a quickcheck-combinators
crate would be welcome :thinking:
Since rand::RngCore
is a super-trait of quickcheck::Gen
, the intent is that you should be able to use any of the methods on RngCore
and Rng
. Specifically, the latter is probably where you'll find your combinators.
Those pointers are super helpful @BurntSushi! I'll have to play with quickcheck
again and get a better feel for it :) Being new to Rust means I'm still getting a feel for the ecosystem and how things are organised. I'll try make a PR with any helpful docs/tutorials if I come up with anything.
Thanks for the response :heart:
Hey hey :wave:
I'm using your library coming fresh into the Rust world after spending time using Haskell. Something that's surprised me looking around is the lack of combinators for writing
Arbitrary
instances. I was able to manage easily forstruct
s because I can just dish out to theArbitrary
instances for base types likeString
. But as soon as I got toenum
I became lost. In Haskell we have things likeoneof
,frequency
, andelements
.Is there idiomatic way to do these things with
quickcheck
? If so, can I help document them? Or would these combinators be welcome in the library?Looking forward to your response and hoping I can help out here :)