weighted combines two generators by choosing between them with probabilities proportional to their supplied weights. It generalizes union: instead of an equal-likelihood Boolean choice, it draws a random probability and compares it with a normalized threshold. section 8.1.5 section 8.6
Selecting with a normalized threshold
def weighted[A](g1: (Gen[A], Double), g2: (Gen[A], Double)): Gen[A] = val g1Threshold = g1(1).abs / (g1(1).abs + g2(1).abs) State(RNG.double).flatMap(d => if d < g1Threshold then g1(0) else g2(0)) The threshold divides the first generator's absolute weight by the sum of both absolute weights. A random double below that threshold selects g1; otherwise it selects g2. section 8.6
The combinator follows the same functional pattern as other dynamic generator choices:
- Use RNG.double to produce the selection value without leaving randomness implicit. section 8.6
- Use flatMap to select the next generator after inspecting that value. section 8.1.5 section 8.6
- Contrast weighted with union, which uses a Boolean coin flip and therefore gives both generators equal likelihood. section 8.1.5 section 8.6
def weighted[A](g1: (Gen[A], Double), g2: (Gen[A], Double)): Gen[A]
Browse the compact weighted combinator signature. section 8.1.5
