functor-combinators-0.3.5.1: Tools for functor combinator-based program design
Copyright(c) Justin Le 2019
LicenseBSD3
Maintainerjustin@jle.im
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Data.Functor.Invariant.DivAp

Description

Provide an invariant functor combinator sequencer, like a combination of Ap and Div.

Since: 0.3.5.0

Synopsis

Chain

newtype DivAp f a Source #

The invariant version of Ap and Div: combines the capabilities of both Ap and Div together.

Conceptually you can think of DivAp f a as a way of consuming and producing as that contains a collection of f xs of different xs. When interpreting this, each a is distributed across all f xs to each interpret, and then re-combined again to produce the resulting a.

You run this in any Applicative context if you want to interpret it covariantly, treating DivAp f a as a producer of a, using runCoDivAp. You can run this in any Divisible context if you you want to interpret it contravariantly, treating DivAp f a as a consumer of as, using runContraDivAp.

Because there is no typeclass that combines both Applicative and Divisible, this type is a little bit tricker to construct/use than Ap or Div.

  • Instead of <*> and divide (typeclass methods), use gather and other variants, which work specifically on this type only.
  • Instead of pure and conquer (typeclass methods), use Knot.
  • Instead of using interpret (to run in a typeclass), either use runCoDivAp (to run in Applicative), runContraDivAp (to run in Divisible), or foldDivAp (to interpret by manually providing handlers)

You can also extract the Ap part out using divApAp, and extract the Div part out using divApDiv.

Note that this type's utility is similar to that of PreT Ap, except PreT Ap lets you use Applicative typeclass methods to assemble it.

Since: 0.3.5.0

Constructors

DivAp 

Fields

Bundled Patterns

pattern Gather :: (a -> (b, c)) -> (b -> c -> a) -> f b -> DivAp f c -> DivAp f a

Match on a non-empty DivAp; contains no fs, but only the terminal value. Analogous to the Ap constructor.

pattern Knot :: a -> DivAp f a

Match on an "empty" DivAp; contains no fs, but only the terminal value. Analogous to Pure.

Instances

Instances details
Invariant (DivAp f) Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

invmap :: (a -> b) -> (b -> a) -> DivAp f a -> DivAp f b #

Inject DivAp Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

inject :: forall (f :: k -> Type). f ~> DivAp f Source #

HFunctor DivAp Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

hmap :: forall (f :: k -> Type) (g :: k -> Type). (f ~> g) -> DivAp f ~> DivAp g Source #

runCoDivAp :: forall f g. Applicative g => (f ~> g) -> DivAp f ~> g Source #

In the covariant direction, we can interpret out of a Chain of Day into any Applicative.

runContraDivAp :: forall f g. Divisible g => (f ~> g) -> DivAp f ~> g Source #

In the contravariant direction, we can interpret out of a Chain of Day into any Divisible.

divApAp :: DivAp f ~> Ap f Source #

Extract the Ap part out of a DivAp, shedding the contravariant bits.

Since: 0.3.2.0

divApDiv :: DivAp f ~> Div f Source #

Extract the Div part out of a DivAp, shedding the covariant bits.

Since: 0.3.2.0

foldDivAp :: (forall x. x -> g x) -> (Day f g ~> g) -> DivAp f ~> g Source #

General-purpose folder of DivAp. Provide a way to handle the identity (pureconquerKnot) and a way to handle a cons (liftA2divideGather).

Since: 0.3.5.0

gather :: (a -> (b, c)) -> (b -> c -> a) -> DivAp f b -> DivAp f c -> DivAp f a Source #

Invariantly combine two DivAps.

Analogous to liftA2 and divise. If there was some typeclass that represented semigroups on invariant Day, this would be the method of that typeclass.

The identity of this is Knot.

Since: 0.3.4.0

gathered :: DivAp f a -> DivAp f b -> DivAp f (a, b) Source #

Convenient wrapper over gather that simply combines the two options in a tuple. Analogous to divised.

Since: 0.3.4.0

assembleDivAp :: NP f as -> DivAp f (NP I as) Source #

Convenient wrapper to build up a DivAp by providing each component of it. This makes it much easier to build up longer chains because you would only need to write the splitting/joining functions in one place.

For example, if you had a data type

data MyType = MT Int Bool String

and an invariant functor Prim (representing, say, a bidirectional parser, where Prim Int is a bidirectional parser for an Int), then you could assemble a bidirectional parser for a MyType@ using:

invmap ((MyType x y z) -> I x :* I y :* I z :* Nil)
       ((I x :* I y :* I z :* Nil) -> MyType x y z) $
  assembleDivAp $ intPrim
                  :* boolPrim
                  :* stringPrim
                  :* Nil

Some notes on usefulness depending on how many components you have:

  • If you have 0 components, use Knot directly.
  • If you have 1 component, use inject or injectChain directly.
  • If you have 2 components, use toListBy or toChain.
  • If you have 3 or more components, these combinators may be useful; otherwise you'd need to manually peel off tuples one-by-one.

assembleDivApRec :: Rec f as -> DivAp f (XRec Identity as) Source #

A version of assembleDivAp using XRec from vinyl instead of NP from sop-core. This can be more convenient because it doesn't require manual unwrapping/wrapping of components.

data MyType = MT Int Bool String

invmap ((MyType x y z) -> x ::& y ::& z ::& RNil)
       ((x ::& y ::& z ::& RNil) -> MyType x y z) $
  assembleDivApRec $ intPrim
                     :& boolPrim
                     :& stringPrim
                     :& Nil

concatDivAp :: NP (DivAp f) as -> DivAp f (NP I as) Source #

A version of assembleDivAp where each component is itself a DivAp.

assembleDivAp (x :* y :* z :* Nil)
  = concatDivAp (injectChain x :* injectChain y :* injectChain z :* Nil)

concatDivApRec :: Rec (DivAp f) as -> DivAp f (XRec Identity as) Source #

A version of concatDivAp using XRec from vinyl instead of NP from sop-core. This can be more convenient because it doesn't require manual unwrapping/wrapping of components.

Nonempty Chain

newtype DivAp1 f a Source #

The invariant version of Ap1 and Div1: combines the capabilities of both Ap1 and Div1 together.

Conceptually you can think of DivAp1 f a as a way of consuming and producing as that contains a (non-empty) collection of f xs of different xs. When interpreting this, each a is distributed across all f xs to each interpret, and then re-combined again to produce the resulting a.

You run this in any Apply context if you want to interpret it covariantly, treating DivAp1 f a as a producer of a, using runCoDivAp1. You can run this in any Divise context if you you want to interpret it contravariantly, treating DivAp1 f a as a consumer of as, using runContraDivAp1.

Because there is no typeclass that combines both Apply and Divise, this type is a little bit tricker to construct/use than Ap1 or Div1.

  • Instead of <.> and divide (typeclass methods), use gather1 and other variants, which work specifically on this type only.
  • Instead of using interpret (to run in a typeclass), either use runCoDivAp1 (to run in Apply), runContraDivAp1 (to run in Divise), or foldDivAp1 (to interpret by manually providing handlers)

You can also extract the Ap1 part out using divApAp1, and extract the Div1 part out using divApDiv1.

Note that this type's utility is similar to that of PreT Ap1, except PreT Ap1 lets you use Apply typeclass methods to assemble it.

Since: 0.3.5.0

Constructors

DivAp1_ 

Fields

Bundled Patterns

pattern DivAp1 :: Invariant f => (a -> (b, c)) -> (b -> c -> a) -> f b -> DivAp f c -> DivAp1 f a

Match on a DivAp1 to get the head and the rest of the items. Analogous to the Ap1 constructor.

Instances

Instances details
Invariant f => Invariant (DivAp1 f) Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

invmap :: (a -> b) -> (b -> a) -> DivAp1 f a -> DivAp1 f b #

Inject DivAp1 Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

inject :: forall (f :: k -> Type). f ~> DivAp1 f Source #

HFunctor DivAp1 Source # 
Instance details

Defined in Data.HFunctor.Chain.Internal

Methods

hmap :: forall (f :: k -> Type) (g :: k -> Type). (f ~> g) -> DivAp1 f ~> DivAp1 g Source #

runCoDivAp1 :: forall f g. Apply g => (f ~> g) -> DivAp1 f ~> g Source #

In the covariant direction, we can interpret out of a Chain1 of Day into any Apply.

runContraDivAp1 :: forall f g. Divise g => (f ~> g) -> DivAp1 f ~> g Source #

In the contravariant direction, we can interpret out of a Chain1 of Day into any Divise.

divApAp1 :: DivAp1 f ~> Ap1 f Source #

Extract the Ap1 part out of a DivAp1, shedding the contravariant bits.

Since: 0.3.2.0

divApDiv1 :: DivAp1 f ~> Div1 f Source #

Extract the Div1 part out of a DivAp1, shedding the covariant bits.

Since: 0.3.2.0

foldDivAp1 :: (f ~> g) -> (Day f g ~> g) -> DivAp1 f ~> g Source #

General-purpose folder of DivAp1. Provide a way to handle the individual leaves and a way to handle a cons ('liftF2diviseGather).

Since: 0.3.5.0

gather1 :: Invariant f => (a -> (b, c)) -> (b -> c -> a) -> DivAp1 f b -> DivAp1 f c -> DivAp1 f a Source #

Invariantly combine two DivAp1s.

Analogous to liftA2 and divise. If there was some typeclass that represented semigroups on invariant Day, this would be the method of that typeclass.

Since: 0.3.4.0

gathered1 :: Invariant f => DivAp1 f a -> DivAp1 f b -> DivAp1 f (a, b) Source #

Convenient wrapper over gather1 that simply combines the two options in a tuple. Analogous to divised.

Since: 0.3.4.0

assembleDivAp1 :: Invariant f => NP f (a ': as) -> DivAp1 f (NP I (a ': as)) Source #

A version of assembleDivAp but for DivAp1 instead. Can be useful if you intend on interpreting it into something with only a Divise or Apply instance, but no Divisible or Applicative.

assembleDivAp1Rec :: Invariant f => Rec f (a ': as) -> DivAp1 f (XRec Identity (a ': as)) Source #

A version of assembleDivAp1 using XRec from vinyl instead of NP from sop-core. This can be more convenient because it doesn't require manual unwrapping/wrapping of components.

concatDivAp1 :: Invariant f => NP (DivAp1 f) (a ': as) -> DivAp1 f (NP I (a ': as)) Source #

A version of concatDivAp but for DivAp1 instead. Can be useful if you intend on interpreting it into something with only a Divise or Apply instance, but no Divisible or Applicative.

concatDivAp1Rec :: Invariant f => Rec (DivAp1 f) (a ': as) -> DivAp1 f (XRec Identity (a ': as)) Source #

A version of concatDivAp1 using XRec from vinyl instead of NP from sop-core. This can be more convenient because it doesn't require manual unwrapping/wrapping of components.

Day Utility

runDayApply :: forall f g h. Apply h => (f ~> h) -> (g ~> h) -> Day f g ~> h Source #

Interpret the covariant part of a Day into a target context h, as long as the context is an instance of Apply. The Apply is used to combine results back together using <*>.

runDayDivise :: forall f g h. Divise h => (f ~> h) -> (g ~> h) -> Day f g ~> h Source #

Interpret the contravariant part of a Day into a target context h, as long as the context is an instance of Divise. The Divise is used to split up the input to pass to each of the actions.