nim_iterator_stream_experiment/monad/lazymonadlaws

Utilities to check whether a type M obeys the monad laws.

This module is meant to be used in test suites. It should not be imported with monadlaws.

M must have:
  • A flatMap[A; B] procedure with the signature (M[A], A -> M[B]) -> M[B].
  • A run[A; R] procedure with the signature (M[A], R) -> A.

Concepts cannot currently be used to implement the monad concept in Nim. See this related issue.

Examples:

Types

LazyMonad[T; R] = concept m
    m.run(R) is T
  Source Edit
LeftIdentitySpec[A; MA; MB; R] = tuple[initial: A, lift: A -> MA, f: A -> MB, runArg: R]
Parameters for the left identity law.   Source Edit
RightIdentitySpec[T; M; R] = tuple[expected: T, lift: T -> M, runArg: R]
Parameters for the right identity law.   Source Edit
AssociativitySpec[A; B; MA; MB; MC; R] = tuple[initial: A, lift: A -> MA, f: A -> MB, g: B -> MC,
                                        runArg: R]
Parameters for the associativity law.   Source Edit
MonadLawsSpec[LA; LMA; LMB; LR; RT; RM; RR; AA; AB; AMA; AMB; AMC; AR] = tuple[
    leftIdentity: LeftIdentitySpec[LA, LMA, LMB, LR],
    rightIdentity: RightIdentitySpec[RT, RM, RR],
    associativity: AssociativitySpec[AA, AB, AMA, AMB, AMC, AR]]
  Source Edit

Funcs

func leftIdentitySpec[A; MA; MB; R](initial: A; lift: A -> MA; f: A -> MB; runArg: R): LeftIdentitySpec[
    A, MA, MB, R]
  • lift: A procedure to lift a value to a monad.
  • f: The procedure passed to flatMap defined by the tested monad type.
  Source Edit
func rightIdentitySpec[T; M; R](expected: T; lift: T -> M; runArg: R): RightIdentitySpec[T,
    M, R]
  • expected: The starting value on the left side of the equation, the final value on the right side.
  • lift: A procedure to lift a value to a monad.
  Source Edit
func associativitySpec[A; B; MA; MB; MC; R](initial: A; lift: A -> MA; f: A -> MB; g: B -> MC;
                                      runArg: R): AssociativitySpec[A, B, MA, MB, MC, R]
  • lift: A procedure to lift a value to a monad.
  • f: The procedure passed to the first flatMap defined by the tested monad type.
  • g: The procedure passed to the second flatMap defined by the tested monad type.
  Source Edit
func monadLawsSpec[LA; LMA; LMB; LR; RT; RM; RR; AA; AB; AMA; AMB; AMC; AR](
    leftIdentity: LeftIdentitySpec[LA, LMA, LMB, LR];
    rightIdentity: RightIdentitySpec[RT, RM, RR];
    associativity: AssociativitySpec[AA, AB, AMA, AMB, AMC, AR]): MonadLawsSpec[LA, LMA,
    LMB, LR, RT, RM, RR, AA, AB, AMA, AMB, AMC, AR]
  Source Edit

Templates

template checkLeftIdentity[A; MA; MB; R](spec: LeftIdentitySpec[A, MA, MB, R]): bool

Checks whether a.lift().flatMap(f).run(r) == f(a).run(r).

Lifting a value a to a monad, binding f to it and running the result should be the same as applying f to a and running the result.

  Source Edit
template checkRightIdentity[T; M; R](spec: RightIdentitySpec[T, M, R]): bool

Checks whether a.lift().flatMap(lift).run(r) == a.lift().run(r).

Lifting a value a, binding the lift procedure to it and running the result should be the same as lifting the value and running the result.

  Source Edit
template checkAssociativity[A; B; MA; MB; MC; R](
    spec: AssociativitySpec[A, B, MA, MB, MC, R]): bool

Checks whether a.lift().flatMap(f).flatMap(g).run(r) == a.lift().flatMap(f.chain(m => m.flatMap(g))).run(r).

Lifting a value a, binding f, then g to it and running the result should be the same as lifting a, binding f.chain(m => m.flatMap(g)) and running the result.

  Source Edit
template checkMonadLaws[LA; LMA; LMB; LR; RT; RM; RR; AA; AB; AMA; AMB; AMC; AR](spec: MonadLawsSpec[
    LA, LMA, LMB, LR, RT, RM, RR, AA, AB, AMA, AMB, AMC, AR]): bool
  Source Edit