effect-ts-laws
Version:
effect-ts law testing using fast-check.
44 lines • 2.9 kB
JavaScript
import { Applicative as AP, SemiApplicative as SA, } from '@effect/typeclass';
import { Applicative as optionApplicative } from '@effect/typeclass/data/Option';
import { identity, pipe } from 'effect';
import { apply, compose } from 'effect/Function';
import { addLawSets, Law, lawTests } from '../../../law.js';
import { monoidLaws } from '../concrete/Monoid.js';
import { withOuterOption } from './compose.js';
import { covariantLaws } from './Covariant.js';
import { unfoldGiven } from './given.js';
/**
* Typeclass laws for `Applicative`.
* @category typeclass laws
*/
export const applicativeLaws = (given, suffix) => {
const { Monoid: monoid, F, fa, equalsA, getEquivalence } = unfoldGiven(given);
return pipe(buildLaws(`Alternative${suffix ?? ''}`, given), pipe(given, covariantLaws, addLawSets), addLawSets(buildLaws(...withOuterOption('Applicative', given, optionApplicative))), pipe({
suffix: 'Applicative.getMonoid()',
a: fa,
F: pipe(monoid, (AP.getMonoid(F))),
equalsA: getEquivalence(equalsA),
}, monoidLaws, addLawSets));
};
const buildLaws = (name, given) => {
const { F, a, fa, equalsFa, equalsFb, equalsFc, ab, fabOf, fbcOf } = unfoldGiven(given);
const [fab, fbc] = [fabOf(F.of), fbcOf(F.of)], [ap, of, map] = [SA.ap(F), F.of, F.map];
return lawTests(name, Law('identity', 'id ▹ of ▹ ap(a) = a', fa)(a => equalsFa(pipe((identity), of, ap(a)), a)), Law('homomorphism', 'ab ▹ of ▹ (a ▹ of ▹ ap) = a ▹ ab ▹ of', a, ab)((a, ab) => equalsFb(pipe(ab, of, ap(of(a))), pipe(a, ab, of))), Law('associative composition', 'fbc ▹ map(compose) ▹ ap(fab) ▹ ap(fa) = fbc ▹ ap(fab ▹ ap(fa))', fa, fab, fbc)((fa, fab, fbc) => {
const left = pipe(fbc, map(bc => compose(bc)), ap(fab), ap(fa));
const right = pipe(fbc, ap(pipe(fab, ap(fa))));
return equalsFc(left, right);
}), Law('interchange', 'fab ▹ ap(of(a)) = a ▹ apply ▹ of ▹ ap(Fab)', a, fab)((a, fab) => {
return equalsFb(pipe(fab, ap(of(a))), pipe(a, apply, (of), ap(fab)));
}), Law('map consistency', 'fa ▹ map(ab) = ab ▹ of ▹ ap(fa)', fa, ab)((fa, ab) => equalsFb(pipe(fa, map(ab)), pipe(ab, F.of, ap(fa)))), Law('product consistency', 'fab ▹ ap(fa) = product(fab, fa) ▹ map(([ab, a]) ⇒ ab(a))', fa, fab)((fa, fab) => equalsFb(pipe(fab, ap(fa)), pipe(F.product(fab, fa), map(([f, a]) => f(a))))),
// Some applicatives do not have monads. For example: when the applicative is
// composed we have no monad for this law.
...('flatMap' in F
? [
Law('flatMap consistency', 'fab ▹ ap(fa) = fab ▹ flatMap(ab ⇒ map(fa, ab))', fa, fab)((fa, fab) => {
const flatMap = F.flatMap;
return equalsFb(ap(fab, fa), pipe(fab, flatMap(ab => map(fa, ab))));
}),
]
: []));
};
//# sourceMappingURL=Applicative.js.map