All files / src/laws/typeclass/parameterized Invariant.ts

100% Statements 48/48
100% Branches 4/4
100% Functions 2/2
100% Lines 48/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 761x   1x 1x   1x   1x             1x 42x 42x   42x 42x 42x 42x 42x 42x   1x 84x 84x 84x 84x 84x 84x 84x 84x 84x 84x   84x 84x 84x 84x 84x 84x 84x   84x 84x 84x 84x 84x 84x 84x 84x 84x 5631x 5631x 5631x 5631x 84x 84x 84x                              
import {addLawSets, Law, lawTests} from '#law'
import {Invariant as IN} from '@effect/typeclass'
import {Covariant as optionInvariant} from '@effect/typeclass/data/Option'
import {flow, identity, pipe} from 'effect'
import type {TypeLambda} from 'effect/HKT'
import {withOuterOption} from './compose.js'
import type {BuildParameterized} from './given.js'
import {unfoldGiven} from './given.js'
import {BuildInternal} from './internal.js'
 
/**
 * Typeclass laws for `Invariant`.
 * @category typeclass laws
 */
export const invariantLaws: BuildParameterized<InvariantTypeLambda> = (
  given,
  suffix?,
) =>
  pipe(
    buildLaws(`Invariant${suffix ?? ''}`, given),
    addLawSets(
      buildLaws(...withOuterOption('Invariant', given, optionInvariant)),
    ),
  )
 
const buildLaws: BuildInternal<InvariantTypeLambda> = (name, given) => {
  const {
    F: {imap},
    fa,
    equalsFa,
    equalsFc,
    ab,
    bc,
    ba,
    cb,
  } = unfoldGiven(given)
 
  return lawTests(
    name,
    Law(
      'identity',
      'imap(id, id) = id',
      fa,
    )(a => equalsFa(imap(a, identity, identity), a)),
 
    Law(
      'composition',
      'a ▹ imap(ab, ba) ▹ imap(bc, cb) = a ▹ imap(bc ∘ ab, ba ∘ cb)',
      fa,
      ab,
      bc,
      ba,
      cb,
    )((a, ab, bc, ba, cb) =>
      equalsFc(
        pipe(a, imap(ab, ba), imap(bc, cb)),
        pipe(a, imap(flow(ab, bc), flow(cb, ba))),
      ),
    ),
  )
}
 
/**
 * Type lambda for the `Invariant` typeclass.
 * @category type lambda
 */
export interface InvariantTypeLambda extends TypeLambda {
  readonly type: IN.Invariant<this['Target'] & TypeLambda>
}
 
declare module './given.js' {
  interface ParameterizedLambdas {
    Invariant: InvariantTypeLambda
  }
}