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.
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.
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.
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