All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.marksman.kraftwerk.CoProducts Maven / Gradle / Ivy

The newest version!
package dev.marksman.kraftwerk;

import com.jnape.palatable.lambda.adt.Either;
import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.These;
import com.jnape.palatable.lambda.adt.Unit;
import dev.marksman.kraftwerk.frequency.FrequencyMap;
import dev.marksman.kraftwerk.weights.BooleanWeights;
import dev.marksman.kraftwerk.weights.EitherWeights;
import dev.marksman.kraftwerk.weights.MaybeWeights;
import dev.marksman.kraftwerk.weights.TernaryWeights;

import static com.jnape.palatable.lambda.adt.Maybe.nothing;
import static dev.marksman.kraftwerk.Generators.constant;
import static dev.marksman.kraftwerk.weights.EitherWeights.rights;
import static dev.marksman.kraftwerk.weights.MaybeWeights.justs;
import static dev.marksman.kraftwerk.weights.TernaryWeights.ternaryWeights;

final class CoProducts {
    private CoProducts() {
    }

    private static final Generator GENERATE_UNIT = constant(Unit.UNIT);
    private static final Generator GENERATE_TRUE = constant(true);
    private static final Generator GENERATE_FALSE = constant(false);

    private static final MaybeWeights DEFAULT_MAYBE_WEIGHTS = justs(9).toNothings(1);
    private static final EitherWeights DEFAULT_EITHER_WEIGHTS = rights(9).toLefts(1);
    private static final TernaryWeights DEFAULT_THESE_WEIGHTS = ternaryWeights();

    static Generator generateUnit() {
        return GENERATE_UNIT;
    }

    static Generator generateBoolean(BooleanWeights weights) {
        int trueWeight = weights.getTrueWeight();
        int falseWeight = weights.getFalseWeight();
        if (trueWeight == falseWeight) {
            return Generators.generateBoolean();
        } else {
            return FrequencyMap.frequencyMap(generateFalse().weighted(falseWeight))
                    .add(generateTrue().weighted(trueWeight))
                    .toGenerator();
        }
    }

    static Generator generateTrue() {
        return GENERATE_TRUE;
    }

    static Generator generateFalse() {
        return GENERATE_FALSE;
    }

    static  Generator> generateMaybe(MaybeWeights weights, Generator g) {
        return FrequencyMap.frequencyMap(generateJust(g).weighted(weights.getJustWeight()))
                .add(CoProducts.generateNothing().weighted(weights.getNothingWeight()))
                .toGenerator();
    }

    static  Generator> generateMaybe(Generator g) {
        return generateMaybe(DEFAULT_MAYBE_WEIGHTS, g);
    }

    static  Generator> generateJust(Generator g) {
        return g.fmap(Maybe::just);
    }

    static  Generator> generateNothing() {
        return constant(nothing());
    }

    static  Generator> generateEither(EitherWeights weights, Generator leftGenerator, Generator rightGenerator) {
        return FrequencyMap.frequencyMap(CoProducts.generateLeft(leftGenerator).weighted(weights.getLeftWeight()))
                .add(CoProducts.generateRight(rightGenerator).weighted(weights.getRightWeight()))
                .toGenerator();
    }

    static  Generator> generateEither(Generator leftGenerator, Generator rightGenerator) {
        return generateEither(DEFAULT_EITHER_WEIGHTS, leftGenerator, rightGenerator);
    }

    static  Generator> generateLeft(Generator g) {
        return g.fmap(Either::left);
    }

    static  Generator> generateRight(Generator g) {
        return g.fmap(Either::right);
    }

    static  Generator> generateThese(Generator generatorA, Generator generatorB) {
        return generateThese(DEFAULT_THESE_WEIGHTS, generatorA, generatorB);
    }

    static  Generator> generateThese(TernaryWeights weights, Generator generatorA, Generator generatorB) {
        return FrequencyMap.frequencyMap(generatorA.fmap(These::a).weighted(weights.getWeightA()))
                .add(generatorB.fmap(These::b).weighted(weights.getWeightB()))
                .add(generatorA.zipWith(These::both, generatorB).weighted(weights.getWeightC()))
                .toGenerator();
    }
}