Copyright | (c) Justin Le 2019 |
---|---|
License | BSD3 |
Maintainer | justin@jle.im |
Stability | experimental |
Portability | non-portable |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
This module contains the useful combinators Pre
and Post
, which
enhances a functor with a "route" to and from the outside world; even if
the functor itself is existentially closed in a functor combinator, the
route will provide line to the outside world for extraction or
injection.
See Pre
and Post
for more information.
Since: 0.3.4.0
Synopsis
- data Pre a f b = (a -> b) :>$<: (f b)
- interpretPre :: Contravariant g => (f ~> g) -> Pre a f b -> g a
- getPre :: Pre a f b -> f b
- retractPre :: Contravariant f => Pre a f b -> f a
- injectPre :: Inject t => (a -> b) -> f b -> t (Pre a f) b
- mapPre :: (c -> a) -> Pre a f b -> Pre c f b
- preDivisible :: (forall m. Monoid m => Interpret t (AltConst m), Divisible g) => (f ~> g) -> t (Pre a f) b -> g a
- preDivise :: (forall m. Semigroup m => Interpret t (AltConst m), Divise g) => (f ~> g) -> t (Pre a f) b -> g a
- preContravariant :: (forall m. Interpret t (AltConst m), Contravariant g) => (f ~> g) -> t (Pre a f) b -> g a
- data Post a f b = (b -> a) :<$>: (f b)
- interpretPost :: Functor g => (f ~> g) -> Post a f b -> g a
- getPost :: Post a f b -> f b
- retractPost :: Functor f => Post a f b -> f a
- injectPost :: Inject t => (b -> a) -> f b -> t (Post a f) b
- mapPost :: (a -> c) -> Post a f b -> Post c f b
- postPlus :: (forall m. Monoid m => Interpret t (AltConst m), Plus g) => (f ~> g) -> t (Post a f) b -> g a
- postAlt :: (forall m. Semigroup m => Interpret t (AltConst m), Alt g) => (f ~> g) -> t (Post a f) b -> g a
- postFunctor :: (forall m. Interpret t (AltConst m), Functor g) => (f ~> g) -> t (Post a f) b -> g a
- newtype PreT t f a = PreT {}
- preDivisibleT :: (forall m. Monoid m => Interpret t (AltConst m), Divisible g) => (f ~> g) -> PreT t f ~> g
- preDiviseT :: (forall m. Semigroup m => Interpret t (AltConst m), Divise g) => (f ~> g) -> PreT t f ~> g
- preContravariantT :: (forall m. Interpret t (AltConst m), Contravariant g) => (f ~> g) -> PreT t f ~> g
- newtype PostT t f a = PostT {}
- postPlusT :: (forall m. Monoid m => Interpret t (AltConst m), Plus g) => (f ~> g) -> PostT t f ~> g
- postAltT :: (forall m. Semigroup m => Interpret t (AltConst m), Alt g) => (f ~> g) -> PostT t f ~> g
- postFunctorT :: (forall m. Interpret t (AltConst m), Functor g) => (f ~> g) -> PostT t f ~> g
Routing Combinators
Contravariant
A useful helper type to use with a covariant functor combinator that
allows you to tag along contravariant access to all f
s inside the
combinator.
Maybe most usefully, it can be used with Ap
. Remember that
is a collection of Ap
f af x
s, with each x existentially wrapped. Now, for
a
, it will be a collection of Ap
(Pre a f) af x
and a -> x
s:
not only each individual part, but a way to "select" that individual
part from the overal a
.
So, you can imagine
as a collection of Ap
(Pre
a f) bf x
that
consumes a
and produces b
.
When a
and b
are the same,
is like the free
invariant sequencer. That is, in a sense, Ap
(Pre
a f) a
contains
both contravariant and covariant sequences side-by-side, consuming
Ap
(Pre
a f) aa
s and also producing a
s.
You can build up these values with injectPre
, and then use whatever
typeclasses your t
normally supports to build it up, like
Applicative
(for Ap
). You can then interpret it into both its
contravariant and covariant contexts:
-- interpret the covariant part runCovariant ::Applicative
g => (f ~> g) -> Ap (Pre a f) a -> g a runCovariant f = interpret (f . getPre) -- interpret the contravariant part runContravariant ::Divisible
g => (f ~> g) -> Ap (Pre a f) a -> g a runContravariant = preDivisible
The PreT
type wraps up
into a type Ap
(Pre
a f) a
, with nice instances/helpers.PreT
Ap
f a
An example of a usage of this in the real world is the unjson library's record type constructor, to implement bidrectional serializers for product types.
(a -> b) :>$<: (f b) infixl 4 |
Instances
HTraversable (Pre a :: (Type -> Type) -> Type -> Type) Source # | |
Defined in Data.HFunctor.Route | |
HFunctor (Pre a :: (Type -> Type) -> Type -> Type) Source # | |
a ~ Void => HBind (Pre a :: (Type -> Type) -> Type -> Type) Source # | This instance is over-contrained ( |
a ~ Void => Inject (Pre a :: (Type -> Type) -> Type -> Type) Source # | This instance is over-contrained ( |
a ~ Void => Interpret (Pre a :: (Type -> Type) -> Type -> Type) (f :: Type -> Type) Source # | |
Functor f => Functor (Pre a f) Source # | |
Contravariant f => Invariant (Pre a f) Source # | |
Defined in Data.HFunctor.Route |
interpretPre :: Contravariant g => (f ~> g) -> Pre a f b -> g a Source #
Interpret a Pre
into a contravariant context, applying the
pre-routing function.
getPre :: Pre a f b -> f b Source #
Drop the pre-routing function and just give the original wrapped value.
retractPre :: Contravariant f => Pre a f b -> f a Source #
injectPre :: Inject t => (a -> b) -> f b -> t (Pre a f) b Source #
Like inject
, but allowing you to provide a pre-routing function.
preDivisible :: (forall m. Monoid m => Interpret t (AltConst m), Divisible g) => (f ~> g) -> t (Pre a f) b -> g a Source #
Run a "pre-routed" t
into a contravariant Divisible
context. To
run it in t
s normal covariant context, use interpret
with getPre
.
This will work for types where there are a possibly-empty collection of
f
s, like:
preDivisible :: Divisible g => (f ~> g) ->Ap
(Pre
a f) b -> g a preDivisible :: Divisible g => (f ~> g) ->ListF
(Pre
a f) b -> g a
preDivise :: (forall m. Semigroup m => Interpret t (AltConst m), Divise g) => (f ~> g) -> t (Pre a f) b -> g a Source #
Run a "pre-routed" t
into a contravariant Divise
context. To
run it in t
s normal covariant context, use interpret
with getPre
.
This will work for types where there are is a non-empty collection of
f
s, like:
preDivise :: Divise g => (f ~> g) ->Ap1
(Pre
a f) b -> g a preDivise :: Divise g => (f ~> g) ->NonEmptyF
(Pre
a f) b -> g a
preContravariant :: (forall m. Interpret t (AltConst m), Contravariant g) => (f ~> g) -> t (Pre a f) b -> g a Source #
Run a "pre-routed" t
into a Contravariant
. To run it in t
s
normal covariant context, use interpret
with getPre
.
This will work for types where there is exactly one f
inside:
preContravariant :: Contravariant g => (f ~> g) ->Step
(Pre
a f) b -> g a preContravariant :: Contravariant g => (f ~> g) ->Coyoneda
(Pre
a f) b -> g a
Covariant
A useful helper type to use with a contravariant functor combinator that
allows you to tag along covariant access to all f
s inside the
combinator.
Maybe most usefully, it can be used with Dec
. Remember that
is a collection of Dec
f af x
s, with each x existentially wrapped. Now, for
a
, it will be a collection of Dec
(Post a f) af x
and x -> a
s:
not only each individual part, but a way to "re-embed" that individual
part into overal a
.
So, you can imagine
as a collection of Dec
(Post
a f) bf x
that
consumes b
and produces a
.
When a
and b
are the same,
is like the free
invariant sequencer. That is, in a sense, Dec
(Post
a f) a
contains
both contravariant and covariant sequences side-by-side, consuming
Dec
(Post
a f) aa
s and also producing a
s.
You can build up these values with injectPre
, and then use whatever
typeclasses your t
normally supports to build it up, like
Conclude
(for Div
). You can then interpret it into both its
contravariant and covariant contexts:
-- interpret the covariant part runCovariant ::Plus
g => (f ~> g) -> Div (Post a f) a -> g a runCovariant f = interpret (f . getPost) -- interpret the contravariant part runContravariant ::Conclude
g => (f ~> g) -> Div (Post a f) a -> g a runContravariant = preDivisible
The PostT
type wraps up
into a type Dec
(Post
a f) a
, with nice instances/helpers.PostT
Dec
f a
An example of a usage of this in the real world is a possible implementation of the unjson library's sum type constructor, to implement bidrectional serializers for sum types.
(b -> a) :<$>: (f b) infixl 4 |
Instances
HTraversable (Post a :: (Type -> Type) -> Type -> Type) Source # | |
Defined in Data.HFunctor.Route | |
HFunctor (Post a :: (Type -> Type) -> Type -> Type) Source # | |
Monoid a => HBind (Post a :: (Type -> Type) -> Type -> Type) Source # | |
Monoid a => Inject (Post a :: (Type -> Type) -> Type -> Type) Source # | |
Monoid a => Interpret (Post a :: (Type -> Type) -> Type -> Type) (f :: Type -> Type) Source # | |
Contravariant f => Contravariant (Post a f) Source # | |
Functor f => Invariant (Post a f) Source # | |
Defined in Data.HFunctor.Route |
interpretPost :: Functor g => (f ~> g) -> Post a f b -> g a Source #
Interpret a Post
into a covariant context, applying the
post-routing function.
getPost :: Post a f b -> f b Source #
Drop the post-routing function and just give the original wrapped value.
retractPost :: Functor f => Post a f b -> f a Source #
injectPost :: Inject t => (b -> a) -> f b -> t (Post a f) b Source #
Like inject
, but allowing you to provide a post-routing function.
postPlus :: (forall m. Monoid m => Interpret t (AltConst m), Plus g) => (f ~> g) -> t (Post a f) b -> g a Source #
Run a "post-routed" t
into a covariant Plus
context. To run it
in t
s normal contravariant context, use interpret
.
This will work for types where there are a possibly-empty collection of
f
s, like:
postPlus :: Plus g => (f ~> g) ->Dec
(Post a f) b -> g a postPlus :: Plus g => (f ~> g) ->Div
(Post a f) b -> g a
postAlt :: (forall m. Semigroup m => Interpret t (AltConst m), Alt g) => (f ~> g) -> t (Post a f) b -> g a Source #
Run a "post-routed" t
into a covariant Alt
context. To run it
in t
s normal contravariant context, use interpret
.
This will work for types where there are is a non-empty collection of
f
s, like:
postAlt :: Alt g => (f ~> g) ->Dec1
(Post a f) b -> g a postAlt :: Alt g => (f ~> g) ->Div1
(Post a f) b -> g a
postFunctor :: (forall m. Interpret t (AltConst m), Functor g) => (f ~> g) -> t (Post a f) b -> g a Source #
Run a "post-routed" t
into a covariant Functor
context. To run it
in t
s normal contravariant context, use interpret
.
This will work for types where there is exactly one f
inside:
postFunctor :: Functor g => (f ~> g) ->Step
(Post a f) b -> g a postFunctor :: Functor g => (f ~> g) ->Coyoneda
(Post a f) b -> g a
Wrapped Invariant
Contravariant
Turn the covariant functor combinator t
into an Invariant
functor combinator; if t f a
"produces" a
s, then
will
both consume and produce PreT
t f aa
s.
You can run this normally as if it were a t f a
by using interpret
;
however, you can also interpret into covariant contexts with
preDivisibleT
, preDiviseT
, and preContravariantT
.
A useful way to use this type is to use normal methods of the underlying
t
to assemble a final t
, then using the PreT
constructor to wrap
it all up.
data MyType = MyType { mtInt :: Int , mtBool :: Bool , mtString :: String } myThing :: PreT Ap MyFunctor MyType myThing = PreT $ MyType $ injectPre mtInt (mfInt :: MyFunctor Int ) * injectPre mtBool (mfBool :: MyFunctor Bool ) * injectPre mtString (mfString :: MyFunctor STring)
See Pre
for more information.
Instances
HTraversable t => HTraversable (PreT t :: (Type -> Type) -> Type -> Type) Source # | |
Defined in Data.HFunctor.Route | |
HFunctor t => HFunctor (PreT t :: (Type -> Type) -> Type -> Type) Source # | |
Inject t => Inject (PreT t :: (Type -> Type) -> Type -> Type) Source # | |
Interpret t f => Interpret (PreT t :: (Type -> Type) -> Type -> Type) (f :: Type -> Type) Source # | |
(HFunctor t, forall x. Functor (t (Pre x f))) => Invariant (PreT t f) Source # | |
Defined in Data.HFunctor.Route |
preDivisibleT :: (forall m. Monoid m => Interpret t (AltConst m), Divisible g) => (f ~> g) -> PreT t f ~> g Source #
Run a
into a contravariant PreT
tDivisible
context. To run it
in t
s normal covariant context, use interpret
.
This will work for types where there are a possibly-empty collection of
f
s, like:
preDivisibleT :: Divisible g => (f ~> g) -> PreTAp
f ~> g preDivisibleT :: Divisible g => (f ~> g) -> PreTListF
f ~> g
preDiviseT :: (forall m. Semigroup m => Interpret t (AltConst m), Divise g) => (f ~> g) -> PreT t f ~> g Source #
preContravariantT :: (forall m. Interpret t (AltConst m), Contravariant g) => (f ~> g) -> PreT t f ~> g Source #
Run a
into a PreT
tContravariant
. To run it in
t
s normal covariant context, use interpret
.
This will work for types where there is exactly one f
inside:
preContravariantT :: Contravariant g => (f ~> g) -> PreTStep
f ~> g preContravariantT :: Contravariant g => (f ~> g) -> PreTCoyoneda
f ~> g
Covariant
Turn the contravariant functor combinator t
into an Invariant
functor combinator; if t f a
"consumes" a
s, then
will
both consume and produce PostT
t f aa
s.
You can run this normally as if it were a t f a
by using interpret
;
however, you can also interpret into covariant contexts with
postPlusT
, postAltT
, and postFunctorT
.
A useful way to use this type is to use normal methods of the underlying
t
to assemble a final t
, then using the PreT
constructor to wrap
it all up.
myThing :: PostT Dec MyFunctor (Either Int Bool) myThing = PostT $ decided $ (injectPost Left (mfInt :: MyFunctor Int )) (injectPost Right (mfBool :: MyFunctor Bool))
See Post
for more information.
Instances
HTraversable t => HTraversable (PostT t :: (Type -> Type) -> Type -> Type) Source # | |
Defined in Data.HFunctor.Route | |
HFunctor t => HFunctor (PostT t :: (Type -> Type) -> Type -> Type) Source # | Since: 0.3.4.2 |
Inject t => Inject (PostT t :: (Type -> Type) -> Type -> Type) Source # | Since: 0.3.4.2 |
Interpret t f => Interpret (PostT t :: (Type -> Type) -> Type -> Type) (f :: Type -> Type) Source # | Since: 0.3.4.2 |
(HFunctor t, forall x. Contravariant (t (Post x f))) => Invariant (PostT t f) Source # | |
Defined in Data.HFunctor.Route |
postPlusT :: (forall m. Monoid m => Interpret t (AltConst m), Plus g) => (f ~> g) -> PostT t f ~> g Source #
postAltT :: (forall m. Semigroup m => Interpret t (AltConst m), Alt g) => (f ~> g) -> PostT t f ~> g Source #