ApplicativeAsk[F, E]
lets you access an E
value in the F[_]
context.
ApplicativeAsk[F, E]
lets you access an E
value in the F[_]
context.
Intuitively, this means that an E
value is required as an input to get "out" of the F[_]
context.
ApplicativeAsk[F, E]
has one external law:
def askAddsNoEffects[A](fa: F[A]) = { (ask *> fa) <-> fa }
ApplicativeAsk[F, E]
has one internal law:
def readerIsAskAndMap[A](f: E => A) = { ask.map(f) <-> reader(f) }
ApplicativeLayer[M, Inner]
has the following functionality:
- the capability to lift values from the Applicative
Inner
to the Applicative
M
, preserving the Applicative
structure
- lifts Applicative
isomorphisms in Inner
((Inner ~> Inner, Inner ~> Inner)
)
into Applicative
homomorphisms in M
(M ~> M
).
ApplicativeLayer[M, Inner]
has the following functionality:
- the capability to lift values from the Applicative
Inner
to the Applicative
M
, preserving the Applicative
structure
- lifts Applicative
isomorphisms in Inner
((Inner ~> Inner, Inner ~> Inner)
)
into Applicative
homomorphisms in M
(M ~> M
).
This allows you to "map" a natural transformation over the Inner
inside M
,
but only if you can provide an inverse of that natural transformation.
ApplicativeLayer[M, Inner]
has two external laws:
def layerRespectsPure[A](a: A) = { layer(a.pure[Inner]) <-> a.pure[M] } def layerRespectsAp[A, B](m: Inner[A])(f: Inner[A => B]) = { layer(m).ap(layer(f)) <-> layer(m.ap(f)) }
ApplicativeLayerFunctor
is the capability to lift Applicative
homomorphisms
in Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
ApplicativeLayerFunctor
is the capability to lift Applicative
homomorphisms
in Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
ApplicativeLayerFunctor[M, Inner]
has no additional laws.
ApplicativeLocal[F, E]
lets you alter the E
value that is observed by an F[A]
value
using ask
; the modification can only be observed from within that F[A]
value.
ApplicativeLocal[F, E]
lets you alter the E
value that is observed by an F[A]
value
using ask
; the modification can only be observed from within that F[A]
value.
ApplicativeLocal[F, E]
has three external laws:
def askReflectsLocal(f: E => E) = { local(ask)(f) <-> ask map f } def localPureIsPure[A](a: A, f: E => E) = { local(f)(pure(a)) <-> pure(a) } def localDistributesOverAp[A, B](fa: F[A], ff: F[A => B], f: E => E) = { local(f)(ff ap fa) <-> local(f)(ff) ap local(f)(fa) }
ApplicativeLocal
has one internal law:
def scopeIsLocalConst(fa: F[A], e: E) = { scope(e)(fa) <-> local(_ => e)(fa) }
FunctorEmpty[F]
allows you to map
and filter out elements simultaneously.
FunctorEmpty[F]
allows you to map
and filter out elements simultaneously.
FunctorEmpty
has two external laws:
def mapFilterComposition[A, B, C](fa: F[A], f: A => Option[B], g: B => Option[C]) = { val lhs: F[C] = fa.mapFilter(f).mapFilter(g) val rhs: F[C] = fa.mapFilter(a => f(a).flatMap(g)) lhs <-> rhs } def mapFilterMapConsistency[A, B](fa: F[A], f: A => B) = { fa.mapFilter(f andThen (_.some)) <-> fa.map(f) }
FunctorEmpty
has three internal laws:
def collectConsistentWithMapFilter[A, B](fa: F[A], f: PartialFunction[A, B]) = { collect(fa)(f) <-> mapFilter(fa)(f.lift) } def flattenOptionConsistentWithMapFilter[A](fa: F[Option[A]]) = { flattenOption(fa) <-> mapFilter(fa)(identity) } def filterConsistentWithMapFilter[A](fa: F[A], f: A => Boolean) = { filter(fa)(f) <-> mapFilter(fa)(a => if (f(a)) Some(a) else None) }
FunctorLayer[M, Inner]
has the following functionality:
- lifts values from the Functor
Inner
to the Functor
M
.
FunctorLayer[M, Inner]
has the following functionality:
- lifts values from the Functor
Inner
to the Functor
M
.
- lifts Functor
isomorphisms in Inner
((Inner ~> Inner, Inner ~> Inner)
)
into Functor
homomorphisms in M
(M ~> M
).
This allows you to "map" a natural transformation over the Inner
inside M
,
but only if you can provide an inverse of that natural transformation.
FunctorLayer[M, Inner]
has two external laws:
def mapForwardRespectsLayer[A](in: Inner[A])(forward: Inner ~> Inner, backward: Inner ~> Inner) = { layer(forward(in)) <-> layerImapK(layer(in))(forward, backward) } def layerImapRespectsId[A](in: M[A]) = { in <-> layerImapK(in)(FunctionK.id, FunctionK.id) }
FunctorLayer
has one free law, i.e. a law guaranteed by parametricity:
def layerRespectsMap[A, B](in: Inner[A])(f: A => B) = { layer(in.map(f)) <-> layer(in).map(f) } // this is free because all `FunctionK`'s (including `layer`, despite not being an instance of the class) // are natural transformations (i.e., they follow this law exactly)
FunctorLayerFunctor
is the capability to lift Functor
homomorphisms in
Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
FunctorLayerFunctor
is the capability to lift Functor
homomorphisms in
Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
FunctorLayerFunctor[M, Inner]
has two external laws:
def layerMapRespectsLayerImapK[A](ma: M[A])(forward: Inner ~> Inner, backward: Inner ~> Inner) = { layerImapK(ma)(forward, backward) <-> layerMapK(ma)(forward) } def layerMapRespectsLayer[A](in: Inner[A])(forward: Inner ~> Inner) = { layer(forward(in)) <-> layerMapK(layer(in))(forward) }
FunctorLayerFunctor[M, Inner]
has one free law, that is,
one law guaranteed by other laws and parametricity:
def layerMapRespectsId[A](in: M[A]) = { in <-> layerImapK(in)(FunctionK.id, FunctionK.id) } Justification: layerImapK(in)(FunctionK.id, FunctionK.id) <-> in [by layerMapRespectsLayerImapK[A]] layerMapK(in)(FunctionK.id) <-> layerImapK(FunctionK.id, FunctionK.id) [by layerImapRespectsId[A]]
FunctorListen[F, L]
is a function F[A] => F[(A, L)]
which exposes some state
that is contained in all F[A]
values, and can be modified using tell
.
FunctorListen[F, L]
is a function F[A] => F[(A, L)]
which exposes some state
that is contained in all F[A]
values, and can be modified using tell
.
FunctorListen
has two external laws:
def listenRespectsTell(l: L) = { listen(tell(l)) <-> tell(l).as(((), l)) } def listenAddsNoEffects(fa: F[A]) = { listen(fa).map(_._1) <-> fa }
FunctorListen
has one internal law:
def listensIsListenThenMap(fa: F[A], f: L => B) = { listens(fa)(f) <-> listen(fa).map { case (a, l) => (a, f(l)) } }
FunctorRaise[F, E]
expresses the ability to raise errors of type E
in a functorial F[_]
context.
FunctorRaise[F, E]
expresses the ability to raise errors of type E
in a functorial F[_]
context.
This means that a value of type F[A]
may contain no A
values but instead an E
error value,
and further map
calls will not have any values to execute the passed function on.
FunctorRaise
has no external laws.
FunctorRaise
has two internal laws:
def catchNonFatalDefault[A](a: => A)(f: Throwable => E)(implicit A: Applicative[F]) = { catchNonFatal(a)(f) <-> try { A.pure(a) } catch { case NonFatal(ex) => raise(f(ex)) } } def ensureDefault[A](fa: F[A])(error: => E)(predicate: A => Boolean)(implicit A: Monad[F]) = { ensure(fa)(error)(predicate) <-> for { a <- fa _ <- if (predicate(a)) pure(()) else raise(error) } yield a }
FunctorRaise
has one free law, i.e. a law guaranteed by parametricity:
def failThenFlatMapFails[A, B](ex: E, f: A => F[B]) = { fail(ex).flatMap(f) <-> fail(ex) } guaranteed by: fail[X](ex) <-> fail[F[Y]](ex) // parametricity fail[X](ex).map(f) <-> fail[F[Y]](ex) // map must have no effect, because there's no X value fail[X](ex).map(f).join <-> fail[F[Y]].join // add join to both sides fail(ex).flatMap(f) <-> fail(ex) // join is equal, because there's no inner value to flatten effects from // QED.
FunctorTell[F, L]
is the ability to "log" values L
inside a context F[_]
, as an effect.
FunctorTell[F, L]
is the ability to "log" values L
inside a context F[_]
, as an effect.
FunctorTell
has no external laws.
FunctorTell
has one internal law:
def writerIsTellAndMap(a: A, l: L) = { (tell(l) as a) <-> writer(a, l) } def tupleIsWriterFlipped(a: A, l: L) = { writer(a, l) <-> tuple((l, a)) }
MonadLayer[M, Inner]
has the following functionality:
- lifts values from the Monad
Inner
to the Monad
M
.
MonadLayer[M, Inner]
has the following functionality:
- lifts values from the Monad
Inner
to the Monad
M
.
- lifts Monad
isomorphisms in Inner
((Inner ~> Inner, Inner ~> Inner)
)
into Monad
homomorphisms in M
(M ~> M
).
This allows you to "map" a natural transformation over the Inner
inside M
,
but only if you can provide an inverse of that natural transformation.
MonadLayer
has one external law:
def layerRespectsFlatMap[A, B](m: Inner[A])(f: A => Inner[B]) = { layer(m).flatMap(f andThen layer) <-> layer(m.flatMap(f)) }
MonadLayerControl is possible to use to access lower monad layers in invariant position, as in so-called "control operations".
MonadLayerControl is possible to use to access lower monad layers in invariant position, as in so-called "control operations".
Three external laws:
def layerMapRespectsLayerControl[A](m: M[A], f: Inner ~> Inner) = { layerMapK(m)(f) <-> layerControl(run => f(run(m)).flatMap(restore) } def distributionLaw[A](nt: State ~> State, st: State[A]) = { restore(nt(st)) <-> layerControl[State[A]](_ (restore(st)).map(nt(_))).flatMap(restore) } def layerControlIdentity[A](ma: M[A]) = { ma <-> layerControl[Inner[State[A]]] { cps => cps(ma).pure[Inner] }.flatMap(layer).flatMap(restore) }
MonadLayerFunctor
is the capability to lift Monad
homomorphisms
in Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
MonadLayerFunctor
is the capability to lift Monad
homomorphisms
in Inner
(Inner ~> Inner
) into homomorphisms in M
(Inner ~> Inner
).
MonadLayerFunctor[M, Inner]
has no additional laws.
MonadState[F, S]
is the capability to access and modify a state value
from inside the F[_]
context, using set(s: S): F[Unit]
and get: F[S]
.
MonadState[F, S]
is the capability to access and modify a state value
from inside the F[_]
context, using set(s: S): F[Unit]
and get: F[S]
.
MonadState has four external laws:
def getThenSetDoesNothing = { get >>= set <-> pure(()) } def setThenGetReturnsSetted(s: S) = { set(s) *> get <-> set(s) *> pure(s) } def setThenSetSetsLast(s1: S, s2: S) = { set(s1) *> set(s2) <-> set(s2) } def getThenGetGetsOnce = { get *> get <-> get }
MonadState
has two internal law:
def modifyIsGetThenSet(f: S => S) = { modify(f) <-> (inspect(f) flatMap set) } def inspectLaw[A](f: S => A) = { inspect(f) <-> (get map f) }
TraverseEmpty
, also known as Witherable
, represents list-like structures
that can essentially have a traverse
and a filter
applied as a single
combined operation (traverseFilter
).
TraverseEmpty
, also known as Witherable
, represents list-like structures
that can essentially have a traverse
and a filter
applied as a single
combined operation (traverseFilter
).
TraverseEmpty
has two external laws:
def traverseFilterIdentity[G[_]: Applicative, A](fa: F[A]) = { fa.traverseFilter(_.some.pure[G]) <-> fa.pure[G] } def traverseFilterComposition[A, B, C, M[_], N[_]](fa: F[A], f: A => M[Option[B]], g: B => N[Option[C]] )(implicit M: Applicative[M], N: Applicative[N] ) = { val lhs = Nested[M, N, F[C]](fa.traverseFilter(f).map(_.traverseFilter(g))) val rhs: Nested[M, N, F[C]] = fa.traverseFilter[NestedC[M, N]#l, C](a => Nested[M, N, Option[C]](f(a).map(_.traverseFilter(g))) ) lhs <-> rhs }
TraverseEmpty
has one internal law:
def filterAConsistentWithTraverseFilter[G[_]: Applicative, A](fa: F[A], f: A => G[Boolean]) = { filterA(fa)(f) <-> fa.traverseFilter(a => G.map(f(a))(if (_) Some(a) else None)) }
Based on Haskell's Data.Witherable