functor-combinators 0.3.2.0 → 0.3.3.0
raw patch · 9 files changed
+229/−223 lines, 9 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.Functor.Combinator: divideN :: Divisible f => NP f as -> f (NP I as)
- Data.Functor.Combinator: divideNRec :: Divisible f => Rec f as -> f (XRec Identity as)
- Data.Functor.Combinator: diviseN :: Divise f => NP f (a : as) -> f (NP I (a : as))
- Data.Functor.Combinator: diviseNRec :: Divise f => Rec f (a : as) -> f (XRec Identity (a : as))
- Data.Functor.Contravariant.Divisible.Free: [Conquer] :: Div f a
- Data.Functor.Contravariant.Divisible.Free: [Div1] :: (a -> (b, c)) -> f b -> Div f c -> Div1 f a
- Data.Functor.Contravariant.Divisible.Free: [Divide] :: (a -> (b, c)) -> f b -> Div f c -> Div f a
- Data.Functor.Contravariant.Divisible.Free: data Div :: (Type -> Type) -> Type -> Type
- Data.Functor.Contravariant.Divisible.Free: data Div1 :: (Type -> Type) -> Type -> Type
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Conclude.Conclude f => Data.Functor.Contravariant.Conclude.Conclude (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Contravariant f => Data.Functor.Contravariant.Contravariant (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Contravariant f => Data.Functor.Contravariant.Divise.Divise (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Contravariant f => Data.Functor.Contravariant.Divisible.Divisible (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Decide.Decide f => Data.Functor.Contravariant.Decide.Decide (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Contravariant.Divisible.Decidable f => Data.Functor.Contravariant.Divisible.Decidable (Control.Applicative.ListF.MaybeF f)
+ Control.Applicative.ListF: instance Data.Functor.Invariant.Invariant f => Data.Functor.Invariant.Invariant (Control.Applicative.ListF.MaybeF f)
+ Data.Functor.Combinator: dsum :: (Foldable t, Divisible f) => t (f a) -> f a
+ Data.Functor.Combinator: dsum1 :: (Foldable1 t, Divise f) => t (f a) -> f a
+ Data.Functor.Combinator: injectContramap :: (Inject t, Contravariant f) => (a -> b) -> f b -> t f a
+ Data.Functor.Combinator: injectMap :: (Inject t, Functor f) => (a -> b) -> f a -> t f b
+ Data.Functor.Contravariant.Divise: (<:>) :: Divise f => f a -> f a -> f a
+ Data.Functor.Contravariant.Divise: dsum1 :: (Foldable1 t, Divise f) => t (f a) -> f a
+ Data.Functor.Contravariant.Divisible.Free: Div :: [Coyoneda f a] -> Div f a
+ Data.Functor.Contravariant.Divisible.Free: Div1 :: NonEmpty (Coyoneda f a) -> Div1 f a
+ Data.Functor.Contravariant.Divisible.Free: [unDiv1] :: Div1 f a -> NonEmpty (Coyoneda f a)
+ Data.Functor.Contravariant.Divisible.Free: [unDiv] :: Div f a -> [Coyoneda f a]
+ Data.Functor.Contravariant.Divisible.Free: newtype Div f a
+ Data.Functor.Contravariant.Divisible.Free: newtype Div1 f a
+ Data.Functor.Contravariant.Divisible.Free: pattern Conquer :: Div f a
+ Data.Functor.Contravariant.Divisible.Free: pattern Div1_ :: (a -> (b, c)) -> f b -> Div f c -> Div1 f a
+ Data.Functor.Contravariant.Divisible.Free: pattern Divide :: (a -> (b, c)) -> f b -> Div f c -> Div f a
+ Data.HFunctor: injectContramap :: (Inject t, Contravariant f) => (a -> b) -> f b -> t f a
+ Data.HFunctor: injectMap :: (Inject t, Functor f) => (a -> b) -> f a -> t f b
- Data.Functor.Contravariant.Divisible.Free: toDiv :: Div1 f a -> Div f a
+ Data.Functor.Contravariant.Divisible.Free: toDiv :: Div1 f ~> Div f
Files
- CHANGELOG.md +25/−0
- functor-combinators.cabal +2/−2
- src/Control/Applicative/ListF.hs +34/−0
- src/Data/Functor/Combinator.hs +18/−104
- src/Data/Functor/Contravariant/Divise.hs +23/−0
- src/Data/Functor/Contravariant/Divisible/Free.hs +89/−98
- src/Data/HBifunctor/Associative.hs +9/−6
- src/Data/HBifunctor/Tensor.hs +12/−13
- src/Data/HFunctor.hs +17/−0
CHANGELOG.md view
@@ -1,6 +1,31 @@ Changelog ========= +Version 0.3.3.0+---------------++*August 11, 2020*++<https://github.com/mstksg/functor-combinators/releases/tag/v0.3.3.0>++* *Control.Applicative.ListF*: Missing contravariant instances added for+ `MaybeF`.+* *Data.HFunctor*: Add `injectMap` and `injectContramap`, two small utility+ functions that represent common patterns in injection and mapping.+* *Data.Functor.Combinator*: Replace `divideN` and related functions with+ `dsum` and `dsum1`, which is an altogether cleaner interface that doesn't+ require heterogenous lists. A part of a larger project on cleaning up+ `Divisible` tools.+* *Data.Functor.Contravariant.Divise*: Add useful utility functions `dsum`+ and `<:>`, which makes the type of `divise` closer to that of `<|>` and+ `asum`.+* *Data.Functor.Contravariant.Divisible.Free*: Implement `Div` in terms of a+ list, instead of the mirrored `Ap`. Should make it much easier to use,+ although a less-than-ideal `Coyoneda` is required to keep it compatible+ with the contravariant `Day` in *kan-extensions*. Added patterns to+ recover the original interface.++ Version 0.3.2.0 ---------------
functor-combinators.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 7c970e85e59e29124e48109889879a7e961d4b9b33326f5a8eaeffcc117f1ced+-- hash: c410805d5e691767b93cffa33046c105029599cb34a0389840cbf00a85077538 name: functor-combinators-version: 0.3.2.0+version: 0.3.3.0 synopsis: Tools for functor combinator-based program design description: Tools for working with /functor combinators/: types that take functors (or other indexed types) and returns a new functor that "enhances" or "mixes"
src/Control/Applicative/ListF.hs view
@@ -245,6 +245,40 @@ empty = zero (<|>) = (<!>) +-- | @since 0.3.3.0+instance Contravariant f => Contravariant (MaybeF f) where+ contramap f (MaybeF x) = MaybeF $ (fmap . contramap) f x++-- | @since 0.3.3.0+instance Invariant f => Invariant (MaybeF f) where+ invmap f g (MaybeF x) = MaybeF $ fmap (invmap f g) x++-- | @since 0.3.3.0+instance Contravariant f => Divise (MaybeF f) where+ divise f (MaybeF x) (MaybeF y) = MaybeF $+ (fmap . contramap) (fst . f) x+ <|> (fmap . contramap) (snd . f) y++-- | @since 0.3.3.0+instance Contravariant f => Divisible (MaybeF f) where+ divide = divise+ conquer = MaybeF Nothing++-- | @since 0.3.3.0+instance Decide f => Decide (MaybeF f) where+ decide f (MaybeF x) (MaybeF y) = MaybeF $+ liftA2 (decide f) x y++-- | @since 0.3.3.0+instance Conclude f => Conclude (MaybeF f) where+ conclude f = MaybeF (Just (conclude f))++-- | @since 0.3.3.0+instance Decidable f => Decidable (MaybeF f) where+ choose f (MaybeF x) (MaybeF y) = MaybeF $+ liftA2 (choose f) x y+ lose f = MaybeF (Just (lose f))+ -- | Picks the first 'Just'. instance Semigroup (MaybeF f a) where MaybeF xs <> MaybeF ys = MaybeF (xs <!> ys)
src/Data/Functor/Combinator.hs view
@@ -46,6 +46,7 @@ , iget, icollect, icollect1 , iapply, ifanout, ifanout1 , getI, collectI+ , injectMap, injectContramap , AltConst(..) -- ** Multi-Functors -- | Classes that deal with two-functor combinators, that "mix" two@@ -109,12 +110,10 @@ , generalize , absorb -- ** Divisible- , divideN- , diviseN+ , dsum+ , dsum1 , concludeN , decideN- , divideNRec- , diviseNRec ) where import Control.Alternative.Free@@ -147,112 +146,27 @@ import Data.HFunctor.Internal import Data.HFunctor.Interpret import GHC.Generics--import qualified Data.SOP as SOP-import qualified Data.Vinyl as V-import qualified Data.Vinyl.Functor as V+import qualified Data.SOP as SOP --- | Convenient helper function to build up a 'Divisible' by providing--- each component of it. This makes it much easier to build up longer--- chains as opposed to nested calls to 'divide' and manually peeling off--- tuples one-by-one.------ For example, if you had a data type------ @--- data MyType = MT Int Bool String--- @------ and a contravariant consumer @Builder@ (representing, say, a way to--- serialize an item, where @intBuilder :: Builder Int@ is a serializer of--- 'Int's), then you could assemble a serializer a @MyType@ using:------ @--- contramap (\(MyType x y z) -> I x :* I y :* I z :* Nil) $--- divideN $ intBuilderj--- :* boolBuilder--- :* stringBuilder--- :* Nil--- @------ Some notes on usefulness depending on how many components you have:------ * If you have 0 components, use 'conquer'.--- * If you have 1 component, use 'inject' directly.--- * If you have 2 components, use 'divide' directly.--- * If you have 3 or more components, these combinators may be useful;--- otherwise you'd need to manually peel off tuples one-by-one.------ @since 0.3.0.0-divideN- :: Divisible f- => SOP.NP f as- -> f (SOP.NP SOP.I as)-divideN = \case- SOP.Nil -> conquer- x SOP.:* xs -> divide- (\case SOP.I y SOP.:* ys -> (y, ys))- x- (divideN xs)---- | A version of 'divideN' defined to work with 'V.XRec', which can--- syntactically cleaner because you don't have to manually wrap/unwrap--- 'SOP.I's.------ Using the example for 'divideN':+-- | Convenient helper function to build up a 'Divisible' by splitting+-- input across many different @f a@s. Most useful when used alongside+-- 'contramap': -- -- @--- data MyType = MT Int Bool String------ contramap (\(MyType x y z) -> x ::& y ::& z ::& Nil) $--- divideNRec $ intBuilderj--- :& boolBuilder--- :& stringBuilder--- :& RNil+-- dsum [+-- contramap get1 x+-- , contramap get2 y+-- , contramap get3 z+-- ] -- @ ----- @since 0.3.0.0-divideNRec- :: Divisible f- => V.Rec f as- -> f (V.XRec V.Identity as)-divideNRec = \case- V.RNil -> conquer- x V.:& xs -> divide- (\case z V.::& zs -> (z, zs))- x- (divideNRec xs)---- | A version of 'divideNRec' that works for non-empty records, and so only--- requires a 'Divise' constraint.------ @since 0.3.0.0-diviseNRec- :: Divise f- => V.Rec f (a ': as)- -> f (V.XRec V.Identity (a ': as))-diviseNRec = \case- x V.:& xs -> case xs of- V.RNil -> contramap (\case z V.::& _ -> z) x- _ V.:& _ -> divise- (\case z V.::& zs -> (z,zs))- x- (diviseNRec xs)---- | A version of 'divideN' that works for non-empty 'SOP.NP', and so only--- requires a 'Divise' constraint.-diviseN- :: Divise f- => SOP.NP f (a ': as)- -> f (SOP.NP SOP.I (a ': as))-diviseN = \case- x SOP.:* xs -> case xs of- SOP.Nil -> contramap (SOP.unI . SOP.hd) x- _ SOP.:* _ -> divise- (\case SOP.I z SOP.:* zs -> (z, zs))- x- (diviseN xs)+-- @since 0.3.3.0+dsum+ :: (Foldable t, Divisible f)+ => t (f a)+ -> f a+dsum = foldr (divide (\x -> (x,x))) conquer -- | Convenient helper function to build up a 'Conclude' by providing -- each component of it. This makes it much easier to build up longer
src/Data/Functor/Contravariant/Divise.hs view
@@ -19,6 +19,8 @@ module Data.Functor.Contravariant.Divise ( Divise(..) , divised+ , (<:>)+ , dsum1 , WrappedDivisible(..) ) where @@ -37,6 +39,7 @@ import qualified Control.Monad.Trans.State.Strict as Strict import qualified Control.Monad.Trans.Writer.Lazy as Lazy import qualified Control.Monad.Trans.Writer.Strict as Strict+import qualified Data.Semigroup.Foldable as F1 import Data.Functor.Apply import Data.Functor.Compose@@ -104,6 +107,26 @@ -- @ divised :: Divise f => f a -> f b -> f (a, b) divised = divise id++-- | The Contravariant version of '<|>': split the same input over two+-- different consumers.+(<:>) :: Divise f => f a -> f a -> f a+x <:> y = divise (\r -> (r,r)) x y++-- | Convenient helper function to build up a 'Divise' by splitting+-- input across many different @f a@s. Most useful when used alongside+-- 'contramap':+--+-- @+-- dsum1 $ contramap get1 x+-- :| [ contramap get2 y+-- , contramap get3 z+-- ]+-- @+--+-- @since 0.3.3.0+dsum1 :: (F1.Foldable1 t, Divise f) => t (f a) -> f a+dsum1 = foldr1 (<:>) . F1.toNonEmpty -- | Wrap a 'Divisible' to be used as a member of 'Divise' newtype WrappedDivisible f a = WrapDivisible { unwrapDivisible :: f a }
src/Data/Functor/Contravariant/Divisible/Free.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DerivingVia #-}+ -- | -- Module : Data.Functor.Contravariant.Divisible.Free -- Copyright : (c) Justin Le 2019@@ -12,10 +14,10 @@ -- -- @since 0.3.0.0 module Data.Functor.Contravariant.Divisible.Free (- Div(..)+ Div(.., Conquer, Divide) , hoistDiv, liftDiv, runDiv , divListF, listFDiv- , Div1(..)+ , Div1(.., Div1_) , hoistDiv1, liftDiv1, toDiv, runDiv1 , div1NonEmptyF, nonEmptyFDiv1 , Dec(..)@@ -28,8 +30,10 @@ import Control.Natural import Data.Bifunctor import Data.Bifunctor.Assoc+import Data.Foldable import Data.Functor.Contravariant import Data.Functor.Contravariant.Conclude+import Data.Functor.Contravariant.Coyoneda import Data.Functor.Contravariant.Decide import Data.Functor.Contravariant.Divise import Data.Functor.Contravariant.Divisible@@ -37,161 +41,148 @@ import Data.HFunctor import Data.HFunctor.Interpret import Data.Kind-import Data.List import Data.List.NonEmpty (NonEmpty(..)) import Data.Void+import qualified Control.Monad.Trans.Compose as CT+import qualified Data.Functor.Contravariant.Day as CD -- | The free 'Divisible'. Used to sequence multiple contravariant -- consumers, splitting out the input across all consumers. ----- Note that @'Div' f@ is essentially @'ListF'--- ('Data.Functor.Contravariant.Coyoneda' f)@, or just @'ListF' f@ in the--- case that @f@ is already contravariant. However, this is left in here--- because it can be more convenient to use if you are working with an--- intermediate @f@ that isn't 'Contravariant'.-data Div :: (Type -> Type) -> Type -> Type where- Conquer :: Div f a- Divide :: (a -> (b, c)) -> f b -> Div f c -> Div f a+-- This type is essentially 'ListF'; the only reason why it has to exist+-- separately outside of 'ListF' is because the current typeclass hierarchy+-- isn't compatible with both the covariant 'Interpret' instance (requiring+-- 'Plus') and the contravariant 'Interpret' instance (requiring+-- 'Divisible').+--+-- The wrapping in 'Coyoneda' is also to provide a usable+-- 'Data.HBifunctor.Associative.Associative' instance for the contravariant+-- 'CD.Day'.+newtype Div f a = Div { unDiv :: [Coyoneda f a] }+ deriving (Contravariant, Divise, Divisible) via (ListF (Coyoneda f))+ deriving (HFunctor, Inject) via (CT.ComposeT ListF Coyoneda) -instance Contravariant (Div f) where- contramap :: forall a b. (a -> b) -> Div f b -> Div f a- contramap f = \case- Conquer -> Conquer- Divide g x xs -> Divide (g . f) x xs instance Invariant (Div f) where invmap _ = contramap -instance Divise (Div f) where- divise f = \case- Conquer -> contramap (snd . f)- Divide g x xs -> Divide (assoc . first g . f) x- . divise id xs-instance Divisible (Div f) where- conquer = Conquer- divide = divise+-- | Pattern matching on an empty 'Div'.+--+-- Before v0.3.3.0, this used to be the concrete constructor of 'Div'.+-- After, it is now an abstract pattern.+pattern Conquer :: Div f a+pattern Conquer = Div [] +-- | Pattern matching on a non-empty 'Div', exposing the raw @f@ instead of+-- having it wrapped in a 'Coyoneda'. This is the analogue of+-- 'Control.Applicative.Free.Pure' and essentially treats the "cons" of the+-- 'Div' as a contravariant day convolution.+--+-- Before v0.3.3.0, this used to be the concrete constructor of 'Div'.+-- After, it is now an abstract pattern.+pattern Divide :: (a -> (b, c)) -> f b -> Div f c -> Div f a+pattern Divide f x xs <- (divDay_ -> Just (CD.Day x xs f))+ where+ Divide f x (Div xs) = Div $ Coyoneda (fst . f) x : (map . contramap) (snd . f) xs+{-# COMPLETE Conquer, Divide #-}++divDay_ :: Div f a -> Maybe (CD.Day f (Div f) a)+divDay_ (Div []) = Nothing+divDay_ (Div (Coyoneda f x : xs)) = Just $ CD.Day x (Div xs) (\y -> (f y, y))+ -- | 'Div' is isomorphic to 'ListF' for contravariant @f@. This witnesses -- one way of that isomorphism.------ Be aware that this is essentially O(n^2). divListF :: forall f. Contravariant f => Div f ~> ListF f-divListF = ListF . unfoldr go- where- go = \case- Conquer -> Nothing- Divide f x xs -> Just ( contramap (fst . f) x- , contramap (snd . f) xs- )+divListF = ListF . map lowerCoyoneda . unDiv -- | 'Div' is isomorphic to 'ListF' for contravariant @f@. This witnesses -- one way of that isomorphism.------ This direction is O(n), unlike 'divListF'. listFDiv :: ListF f ~> Div f-listFDiv = foldr (Divide (\y -> (y,y))) Conquer . runListF+listFDiv = Div . map liftCoyoneda . runListF -- | Map over the undering context in a 'Div'. hoistDiv :: forall f g. (f ~> g) -> Div f ~> Div g-hoistDiv f = go- where- go :: Div f ~> Div g- go = \case- Conquer -> Conquer- Divide g x xs -> Divide g (f x) (go xs)+hoistDiv = hmap -- | Inject a single action in @f@ into a @'Div' f@. liftDiv :: f ~> Div f-liftDiv x = Divide (,()) x Conquer+liftDiv = inject -- | Interpret a 'Div' into a context @g@, provided @g@ is 'Divisible'. runDiv :: forall f g. Divisible g => (f ~> g) -> Div f ~> g-runDiv f = go+runDiv f = foldr go conquer . unDiv where- go :: Div f ~> g- go = \case- Conquer -> conquer- Divide g x xs -> divide g (f x) (go xs)+ go (Coyoneda g x) = divide (\y -> (y,y)) (contramap g (f x)) -instance HFunctor Div where- hmap = hoistDiv-instance Inject Div where- inject = liftDiv instance Divisible f => Interpret Div f where interpret = runDiv -- | The free 'Divise': a non-empty version of 'Div'. ----- Note that @'Div1' f@ is essentially @'NonEmptyF'--- ('Data.Functor.Contravariant.Coyoneda' f)@, or just @'NonEmptyF' f@ in the--- case that @f@ is already contravariant. However, it can be more--- convenient to use if you are working with an intermediate @f@ that isn't--- 'Contravariant'.-data Div1 :: (Type -> Type) -> Type -> Type where- Div1 :: (a -> (b, c)) -> f b -> Div f c -> Div1 f a+-- This type is essentially 'NonEmptyF'; the only reason why it has to exist+-- separately outside of 'NonEmptyF' is because the current typeclass+-- hierarchy isn't compatible with both the covariant 'Interpret' instance+-- (requiring 'Plus') and the contravariant 'Interpret' instance (requiring+-- 'Divisible').+--+-- The wrapping in 'Coyoneda' is also to provide a usable+-- 'Data.HBifunctor.Associative.Associative' instance for the contravariant+-- 'CD.Day'.+newtype Div1 f a = Div1 { unDiv1 :: NonEmpty (Coyoneda f a) }+ deriving (Contravariant, Divise) via (NonEmptyF (Coyoneda f))+ deriving (HFunctor, Inject) via (CT.ComposeT NonEmptyF Coyoneda) -instance Contravariant (Div1 f) where- contramap f (Div1 g x xs) = Div1 (g . f) x xs instance Invariant (Div1 f) where invmap _ = contramap-instance Divise (Div1 f) where- divise f (Div1 g x xs) = Div1 (assoc . first g . f) x- . divise id xs- . toDiv -instance HFunctor Div1 where- hmap = hoistDiv1-instance Inject Div1 where- inject = liftDiv1 instance Divise f => Interpret Div1 f where interpret = runDiv1 +-- | Pattern matching on a 'Div1', exposing the raw @f@ instead of+-- having it wrapped in a 'Coyoneda'. This is the analogue of+-- 'Data.Functor.Apply.Ap1' and essentially treats the "cons" of the+-- 'Div1' as a contravariant day convolution.+--+-- Before v0.3.3.0, this used to be the concrete constructor of 'Div1'.+-- After, it is now an abstract pattern.+--+-- @since 0.3.3.0+pattern Div1_ :: (a -> (b, c)) -> f b -> Div f c -> Div1 f a+pattern Div1_ f x xs <- (div1_->CD.Day x xs f)+ where+ Div1_ f x (Div xs) = Div1 $ Coyoneda (fst . f) x :| (map . contramap) (snd . f) xs+{-# COMPLETE Div1_ #-}++div1_ :: Div1 f ~> CD.Day f (Div f)+div1_ (Div1 (Coyoneda g x :| xs)) = CD.Day x (Div xs) (\y -> (g y, y))+ -- | A 'Div1' is a "non-empty" 'Div'; this function "forgets" the non-empty -- property and turns it back into a normal 'Div'.-toDiv :: Div1 f a -> Div f a-toDiv (Div1 f x xs) = Divide f x xs+toDiv :: Div1 f ~> Div f+toDiv = Div . toList . unDiv1 --- | Map over the undering context in a 'Div1'.+-- | Map over the underlying context in a 'Div1'. hoistDiv1 :: (f ~> g) -> Div1 f ~> Div1 g-hoistDiv1 f (Div1 g x xs) = Div1 g (f x) (hoistDiv f xs)+hoistDiv1 = hmap -- | Inject a single action in @f@ into a @'Div' f@. liftDiv1 :: f ~> Div1 f-liftDiv1 f = Div1 (,()) f Conquer+liftDiv1 = inject -- | Interpret a 'Div1' into a context @g@, provided @g@ is 'Divise'. runDiv1 :: Divise g => (f ~> g) -> Div1 f ~> g-runDiv1 f (Div1 g x xs) = runDiv1_ f g x xs--runDiv1_- :: forall f g a b c. Divise g- => (f ~> g)- -> (a -> (b, c))- -> f b- -> Div f c- -> g a-runDiv1_ f = go+runDiv1 f = foldr1 (divise (\y->(y,y))) . fmap go . unDiv1 where- go :: (x -> (y, z)) -> f y -> Div f z -> g x- go g x = \case- Conquer -> contramap (fst . g) (f x)- Divide h y ys -> divise g (f x) (go h y ys)+ go (Coyoneda g x) = contramap g (f x) -- | 'Div1' is isomorphic to 'NonEmptyF' for contravariant @f@. This -- witnesses one way of that isomorphism.------ Be aware that this is essentially O(n^2). div1NonEmptyF :: Contravariant f => Div1 f ~> NonEmptyF f-div1NonEmptyF (Div1 f x xs) = NonEmptyF $- contramap (fst . f) x- :| runListF (divListF (contramap (snd . f) xs))+div1NonEmptyF = NonEmptyF . fmap lowerCoyoneda . unDiv1 -- | 'Div1' is isomorphic to 'NonEmptyF' for contravariant @f@. This -- witnesses one way of that isomorphism.------ This direction is O(n), unlike 'div1NonEmptyF'. nonEmptyFDiv1 :: NonEmptyF f ~> Div1 f-nonEmptyFDiv1 (NonEmptyF (x :| xs)) =- Div1 (\y -> (y,y)) x (listFDiv (ListF xs))+nonEmptyFDiv1 = Div1 . fmap liftCoyoneda . runNonEmptyF -- | The free 'Decide'. Used to aggregate multiple possible consumers, -- directing the input into an appropriate consumer.@@ -219,7 +210,7 @@ instance Conclude f => Interpret Dec f where interpret = runDec --- | Map over the undering context in a 'Dec'.+-- | Map over the underlying context in a 'Dec'. hoistDec :: forall f g. (f ~> g) -> Dec f ~> Dec g hoistDec f = go where
src/Data/HBifunctor/Associative.hs view
@@ -87,6 +87,7 @@ import Data.List.NonEmpty (NonEmpty(..)) import Data.Void import GHC.Generics+import qualified Data.Functor.Contravariant.Coyoneda as CCY import qualified Data.Functor.Contravariant.Day as CD import qualified Data.Functor.Contravariant.Night as N import qualified Data.Functor.Day as D@@ -393,7 +394,7 @@ -- -- * If @h@ is unconstrained, there are no constraints on @b@ -- * If @h@ must be 'Divise', or 'Divisible', @b@ needs to be an instance of 'Semigroup'--- * If @h@ must be 'Divivisible', then @b@ needs to be an instance of 'Monoid'.+-- * If @h@ must be 'Divisible', then @b@ needs to be an instance of 'Monoid'. -- -- For some constraints (like 'Monad'), this will not be usable. --@@ -482,12 +483,14 @@ associating = isoF CD.assoc CD.disassoc appendNE (CD.Day x y f) = divise f x y- matchNE (Div1 f x xs) = case xs of- Conquer -> L1 $ contramap (fst . f) x- Divide g y ys -> R1 $ CD.Day x (Div1 g y ys) f+ matchNE = hbimap CCY.lowerCoyoneda go . matchNE @(:*:) . NonEmptyF . unDiv1+ where+ go (CCY.Coyoneda f x :*: NonEmptyF xs) = CD.Day x (Div1 xs) (\y -> (f y, y)) - consNE (CD.Day x y f) = Div1 f x (toDiv y)- toNonEmptyBy (CD.Day x y f) = Div1 f x (inject y)+ consNE (CD.Day x (Div1 xs) f) = Div1 . runNonEmptyF . consNE $+ CCY.Coyoneda (fst . f) x :*: contramap (snd . f) (NonEmptyF xs)+ toNonEmptyBy (CD.Day x y f) = Div1 . runNonEmptyF . toNonEmptyBy $+ CCY.Coyoneda (fst . f) x :*: CCY.Coyoneda (snd . f) y -- | @since 0.3.0.0 instance Divise f => SemigroupIn CD.Day f where
src/Data/HBifunctor/Tensor.hs view
@@ -103,6 +103,7 @@ import Data.Kind import Data.List.NonEmpty (NonEmpty(..)) import GHC.Generics+import qualified Data.Functor.Contravariant.Coyoneda as CCY import qualified Data.Functor.Contravariant.Day as CD import qualified Data.Functor.Contravariant.Night as N import qualified Data.Functor.Day as D@@ -580,17 +581,16 @@ elim2 = CD.day2 appendLB (CD.Day x y z) = divide z x y- splitNE (Div1 f x xs) = CD.Day x xs f- splittingLB = isoF to_ from_+ splitNE = go . splitNE @(:*:) . NonEmptyF . unDiv1 where- to_ = \case- Conquer -> L1 Proxy- Divide f x xs -> R1 (CD.Day x xs f)- from_ = \case- L1 Proxy -> Conquer- R1 (CD.Day x xs f) -> Divide f x xs+ go (CCY.Coyoneda f x :*: ListF xs) = CD.Day x (Div xs) (\y -> (f y, y))+ splittingLB = isoF (ListF . unDiv) (Div . runListF) . splittingLB @(:*:) . isoF (hright to_) (hright from_)+ where+ to_ (CCY.Coyoneda f x :*: ListF xs) = CD.Day x (Div xs) (\y -> (f y, y))+ from_ (CD.Day x (Div xs) f) = CCY.Coyoneda (fst . f) x :*: contramap (snd . f) (ListF xs) - toListBy (CD.Day x y z) = Divide z x (inject y)+ toListBy (CD.Day x y f) = Div . runListF . toListBy $+ CCY.Coyoneda (fst . f) x :*: CCY.Coyoneda (snd . f) y -- | Instances of 'Divisible' are monoids in the monoidal category on -- contravariant 'CD.Day'.@@ -759,10 +759,9 @@ -- -- @since 0.3.0.0 instance Matchable CD.Day Proxy where- unsplitNE (CD.Day x xs f) = Div1 f x xs- matchLB = \case- Conquer -> L1 Proxy- Divide f x xs -> R1 (Div1 f x xs)+ unsplitNE (CD.Day x (Div xs) f) = Div1 . runNonEmptyF . unsplitNE $+ CCY.Coyoneda (fst . f) x :*: contramap (snd . f) (ListF xs)+ matchLB = hright (Div1 . runNonEmptyF) . matchLB @(:*:) . ListF . unDiv -- | @since 0.3.0.0 instance Matchable Night Not where
src/Data/HFunctor.hs view
@@ -27,6 +27,9 @@ -- * 'HFunctor' Combinators , HLift(..), retractHLift , HFree(..), foldHFree, retractHFree+ -- * Utility functions+ , injectMap+ , injectContramap ) where import Control.Applicative.Backwards@@ -363,6 +366,20 @@ inject :: f ~> t f {-# MINIMAL inject #-}++-- | A useful wrapper over the common pattern of+-- fmap-before-inject/inject-and-fmap.+--+-- @since 0.3.3.0+injectMap :: (Inject t, Functor f) => (a -> b) -> f a -> t f b+injectMap f = inject . fmap f++-- | A useful wrapper over the common pattern of+-- contramap-before-inject/inject-and-contramap.+--+-- @since 0.3.3.0+injectContramap :: (Inject t, Contravariant f) => (a -> b) -> f b -> t f a+injectContramap f = inject . contramap f -- | 'HBind' is effectively a "higher-order 'Monad'", in the sense that -- 'HFunctor' is a "higher-order 'Functor'".