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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 200x 200x 200x 200x 200x 200x 2x 2x 2x 2x 2x 2x 200x 200x 200x 200x 200x 200x 2x 2x 2x | import {inverse} from '#algebra'
import {Law, LawSet} from '#law'
import {Isomorphism} from '#typeclass'
import {pipe} from 'effect'
import {type Equivalence} from 'effect/Equivalence'
import fc from 'fast-check'
import {defineConcreteLaws} from './given.js'
 
/**
 * Build typeclass laws for isomorphisms that share their `A` type parameter.
 * @category typeclass laws
 */
export const buildIsomorphismLaws =
  <A>(base: BaseIsomorphismGiven<A>) =>
  <Encodings extends BaseEncoding<A>>(encodings: Encodings) => {
    type Entry<K extends keyof Encodings> = [K & string, Encodings[K]]
    const results: LawSet[] = []
    for (const entry of Object.entries(encodings)) {
      const [suffix, entryGiven] = entry as Entry<keyof Encodings>
      const given: IsomorphismGivenFor<A, any> & BaseIsomorphismGiven<A> = {
        ...base,
        ...entryGiven,
      }
      results.push(isomorphismLaws(suffix, given))
    }
 
    return results
  }
 
/**
 * Build typeclass laws for `Isomorphism`.
 * @category typeclass laws
 */
export const isomorphismLaws = <A, B>(
  suffix: string,
  {a, b, equalsA, equalsB, F}: IsomorphismGiven<A, B>,
): LawSet => {
  const [encode, decode] = [Isomorphism.encode(F), Isomorphism.decode(F)]
 
  return defineConcreteLaws(
    'Isomorphism',
    inverse<A, B>(
      {f: encode, g: decode, a, equals: equalsA},
      'F.encode ⚬ F.decode = id',
      'decode/encode identity',
    ),
    inverse<B, A>(
      {f: decode, g: encode, a: b, equals: equalsB},
      'F.decode ⚬ F.encode = id',
      'encode/decode identity',
    ),
 
    Law(
      'reverse compose encode identity',
      'compose(F, reverse(F)).encode = id',
      a,
    )(a =>
      equalsA(
        Isomorphism.encode(
          pipe(F, Isomorphism.reverse, Isomorphism.compose(F)),
        )(a),
        a,
      ),
    ),
 
    Law(
      'reverse compose decode identity',
      'compose(F, reverse(F)).decode = id',
      a,
    )(a =>
      equalsA(
        Isomorphism.decode(
          pipe(F, Isomorphism.reverse, Isomorphism.compose(F)),
        )(a),
        a,
      ),
    ),
  )(suffix)
}
 
declare module './given.js' {
  interface ConcreteLambdas {
    Isomorphism: Isomorphism.IsomorphismTypeLambda
  }
}
 
export type IsomorphismGiven<A, B> = IsomorphismGivenFor<A, B> &
  BaseIsomorphismGiven<A>
 
/**
 * Record of arguments required to test several encodings of the type `A`.  Each
 * `Isomorphism` requires an equivalence and an arbitrary for the encoded type,
 * where the key is the encoding name. As all the encodings share a decoded
 * type, only a single arbitrary/equivalence of `A` is required.
 * @category typeclass laws
 */
export type BaseEncoding<A> = Record<string, IsomorphismGivenFor<A, any>>
 
/**
 * Arguments required to test a single `Isomorphism<A,B>`.
 * @category typeclass laws
 */
export interface IsomorphismGivenFor<A, B> {
  /** An equivalence for the decoded values of the isomorphism. */
  equalsB: Equivalence<B>
 
  /** An arbitrary for the decoded values of the isomorphism. */
  b: fc.Arbitrary<B>
 
  /** Instance of the typeclass under test. */
  F: Isomorphism.Isomorphism<A, B>
}
 
/**
 * Shared arguments required for testing an `Isomorphism` with a decoded type
 * `A`.
 * @category typeclass laws
 */
export interface BaseIsomorphismGiven<A> {
  /** An equivalence for the decoded value of the `Isomorphism` of type `A`. */
  equalsA: Equivalence<A>
 
  /** An arbitrary for the decoded value of the `Isomorphism` of type `A`. */
  a: fc.Arbitrary<A>
}
  |