| Copyright | (c) Justin Le 2025 |
|---|---|
| License | BSD3 |
| Maintainer | justin@jle.im |
| Stability | experimental |
| Portability | non-portable |
| Safe Haskell | None |
| Language | Haskell2010 |
Data.HFunctor
Description
This module provides abstractions for working with unary functor combinators.
Principally, it defines the HFunctor itself, as well as some classes that expose extra functionality that some HFunctors have (Inject and HBind).
See Data.HFunctor.Interpret for tools to use HFunctors as functor combinators that can represent interpretable schemas, and Data.HBifunctor for an abstraction over binary functor combinators.
Synopsis
- class HFunctor (t :: (k -> Type) -> k1 -> Type) where
- overHFunctor :: forall {k1} {k2} (t :: (k1 -> Type) -> k2 -> Type) (f :: k1 -> Type) (g :: k1 -> Type). HFunctor t => (f <~> g) -> t f <~> t g
- class HFunctor t => Inject (t :: (k -> Type) -> k -> Type) where
- class Inject t => HBind (t :: (k -> Type) -> k -> Type) where
- data ProxyF (f :: k) (a :: k1) = ProxyF
- newtype ConstF e (f :: k) (a :: k1) = ConstF {
- getConstF :: e
- data HLift (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (a :: k)
- retractHLift :: forall {k} t (f :: k -> Type) (a :: k). Inject t => HLift t f a -> t f a
- data HFree (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (a :: k)
- foldHFree :: forall {k} (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (g :: k -> Type). HFunctor t => (f ~> g) -> (t g ~> g) -> HFree t f ~> g
- retractHFree :: forall {k} t (f :: k -> Type) (a :: k). HBind t => HFree t f a -> t f a
- injectMap :: (Inject t, Functor f) => (a -> b) -> f a -> t f b
- injectContramap :: (Inject t, Contravariant f) => (a -> b) -> f b -> t f a
Documentation
class HFunctor (t :: (k -> Type) -> k1 -> Type) where Source #
An HFunctor can be thought of a unary "functor transformer" --- a basic functor combinator. It takes a functor as input and returns a functor as output.
It "enhances" a functor with extra structure (sort of like how a monad transformer enhances a Monad with extra structure).
As a uniform inteface, we can "swap the underlying functor" (also sometimes called "hoisting"). This is what hmap does: it lets us swap out the f in a t f for a t g.
For example, the free monad Free takes a Functor and returns a new Functor. In the process, it provides a monadic structure over f. hmap lets us turn a into a Free f: a monad built over Free gf can be turned into a monad built over g.
For the ability to move in and out of the enhanced functor, see Inject and Interpret.
This class is similar to MFunctor from Control.Monad.Morph, but instances must work without a Monad constraint.
This class is also found in the hschema library with the same name.
Methods
hmap :: forall (f :: k -> Type) (g :: k -> Type). (f ~> g) -> t f ~> t g Source #
If we can turn an f into a g, then we can turn a t f into a t g.
It must be the case that
hmapid== id
Essentially, t f adds some "extra structure" to f. hmap must swap out the functor, without affecting the added structure.
For example, is essentially a list of ListF f af as. If we hmap to swap out the f as for g as, then we must ensure that the "added structure" (here, the number of items in the list, and the ordering of those items) remains the same. So, hmap must preserve the number of items in the list, and must maintain the ordering.
The law is a way of formalizing this property.hmap id == id
Instances
overHFunctor :: forall {k1} {k2} (t :: (k1 -> Type) -> k2 -> Type) (f :: k1 -> Type) (g :: k1 -> Type). HFunctor t => (f <~> g) -> t f <~> t g Source #
Lift an isomorphism over an HFunctor.
Essentailly, if f and g are isomorphic, then so are t f and t g.
class HFunctor t => Inject (t :: (k -> Type) -> k -> Type) where Source #
A typeclass for HFunctors where you can "inject" an f a into a t f a:
inject :: f a -> t f a If you think of t f a as an "enhanced f", then inject allows you to use an f as its enhanced form.
With the exception of directly pattern matching on the result, inject itself is not too useful in the general case without Interpret to allow us to interpret or retrieve back the f.
Methods
inject :: forall (f :: k -> Type). f ~> t f Source #
Lift from f into the enhanced t f structure. Analogous to lift from MonadTrans.
Note that this lets us "lift" a f a; if you want to lift an a with a -> t f a, check if t f is an instance of Applicative or Pointed.
Instances
class Inject t => HBind (t :: (k -> Type) -> k -> Type) where Source #
HBind is effectively a "higher-order Monad", in the sense that HFunctor is a "higher-order Functor".
It can be considered a typeclass for HFunctors that you can bind continuations to, nautraluniversal over all ffunctors. They work "for all functors" you lift, without requiring any constraints.
It is very similar to Interpret, except Interpret has the ability to constrain the contexts to some typeclass.
The main law is that binding inject should leave things unchanged:
hbindinject==id
But hbind should also be associatiatve, in a way that makes
hjoin. hjoin = hjoin .hmaphjoin
That is, squishing a t (t (t f)) a into a t f a can be done "inside" first, then "outside", or "outside" first, then "inside".
Note that these laws are different from the Interpret laws, so we often have instances where hbind and interpret (though they both may typecheck) produce different behavior.
This class is similar to MMonad from Control.Monad.Morph, but instances must work without a Monad constraint.
Methods
hbind :: forall (f :: k -> Type) (g :: k -> Type). (f ~> t g) -> t f ~> t g Source #
Bind a continuation to a t f into some context g.
hjoin :: forall (f :: k -> Type). t (t f) ~> t f Source #
Collapse a nested t (t f) into a single t f.
Instances
Simple instances
data ProxyF (f :: k) (a :: k1) Source #
The functor combinator that forgets all structure in the input. Ignores the input structure and stores no information.
Acts like the "zero" with respect to functor combinator composition.
ComposeTProxyF f ~ ProxyFComposeTf ProxyF ~ ProxyF
It can be injected into (losing all information), but it is impossible to ever retract or interpret it.
This is essentially .ConstF ()
Constructors
| ProxyF |
Instances
| HTraversable (ProxyF :: (k -> Type) -> k1 -> Type) Source # | |
Defined in Data.HFunctor.HTraversable | |
| HFunctor (ProxyF :: (k -> Type) -> k1 -> Type) Source # | |
| HBind (ProxyF :: (k -> Type) -> k -> Type) Source # | |
| Inject (ProxyF :: (k -> Type) -> k -> Type) Source # | |
| Foldable (ProxyF f :: Type -> Type) Source # | |
Defined in Data.HFunctor Methods fold :: Monoid m => ProxyF f m -> m # foldMap :: Monoid m => (a -> m) -> ProxyF f a -> m # foldMap' :: Monoid m => (a -> m) -> ProxyF f a -> m # foldr :: (a -> b -> b) -> b -> ProxyF f a -> b # foldr' :: (a -> b -> b) -> b -> ProxyF f a -> b # foldl :: (b -> a -> b) -> b -> ProxyF f a -> b # foldl' :: (b -> a -> b) -> b -> ProxyF f a -> b # foldr1 :: (a -> a -> a) -> ProxyF f a -> a # foldl1 :: (a -> a -> a) -> ProxyF f a -> a # elem :: Eq a => a -> ProxyF f a -> Bool # maximum :: Ord a => ProxyF f a -> a # minimum :: Ord a => ProxyF f a -> a # | |
| Eq1 (ProxyF f :: Type -> Type) Source # | |
| Ord1 (ProxyF f :: Type -> Type) Source # | |
Defined in Data.HFunctor | |
| Read1 (ProxyF f :: Type -> Type) Source # | |
Defined in Data.HFunctor | |
| Show1 (ProxyF f :: Type -> Type) Source # | |
| Contravariant (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Traversable (ProxyF f :: Type -> Type) Source # | |
| Functor (ProxyF f :: Type -> Type) Source # | |
| Decidable (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Divisible (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Conclude (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Decide (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Divise (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
| Invariant (ProxyF f :: Type -> Type) Source # | Since: 0.3.0.0 |
Defined in Data.HFunctor | |
| (Typeable f, Typeable a, Typeable k1, Typeable k2) => Data (ProxyF f a) Source # | |
Defined in Data.HFunctor Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> ProxyF f a -> c (ProxyF f a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (ProxyF f a) # toConstr :: ProxyF f a -> Constr # dataTypeOf :: ProxyF f a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (ProxyF f a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (ProxyF f a)) # gmapT :: (forall b. Data b => b -> b) -> ProxyF f a -> ProxyF f a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ProxyF f a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ProxyF f a -> r # gmapQ :: (forall d. Data d => d -> u) -> ProxyF f a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> ProxyF f a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> ProxyF f a -> m (ProxyF f a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> ProxyF f a -> m (ProxyF f a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> ProxyF f a -> m (ProxyF f a) # | |
| Generic (ProxyF f a) Source # | |
Defined in Data.HFunctor | |
| Read (ProxyF f a) Source # | |
| Show (ProxyF f a) Source # | |
| Eq (ProxyF f a) Source # | |
| Ord (ProxyF f a) Source # | |
| type Rep (ProxyF f a) Source # | |
newtype ConstF e (f :: k) (a :: k1) Source #
Functor combinator that forgets all structure on the input, and instead stores a value of type e.
Like ProxyF, acts like a "zero" with functor combinator composition.
It can be injected into (losing all information), but it is impossible to ever retract or interpret it.
Instances
| HTraversable (ConstF e :: (k -> Type) -> k1 -> Type) Source # | |||||
Defined in Data.HFunctor.HTraversable | |||||
| HFunctor (ConstF e :: (k -> Type) -> k1 -> Type) Source # | |||||
| Monoid e => Inject (ConstF e :: (k -> Type) -> k -> Type) Source # | |||||
| Foldable (ConstF e f :: Type -> Type) Source # | |||||
Defined in Data.HFunctor Methods fold :: Monoid m => ConstF e f m -> m # foldMap :: Monoid m => (a -> m) -> ConstF e f a -> m # foldMap' :: Monoid m => (a -> m) -> ConstF e f a -> m # foldr :: (a -> b -> b) -> b -> ConstF e f a -> b # foldr' :: (a -> b -> b) -> b -> ConstF e f a -> b # foldl :: (b -> a -> b) -> b -> ConstF e f a -> b # foldl' :: (b -> a -> b) -> b -> ConstF e f a -> b # foldr1 :: (a -> a -> a) -> ConstF e f a -> a # foldl1 :: (a -> a -> a) -> ConstF e f a -> a # toList :: ConstF e f a -> [a] # null :: ConstF e f a -> Bool # length :: ConstF e f a -> Int # elem :: Eq a => a -> ConstF e f a -> Bool # maximum :: Ord a => ConstF e f a -> a # minimum :: Ord a => ConstF e f a -> a # | |||||
| Eq e => Eq1 (ConstF e f :: Type -> Type) Source # | |||||
| Ord e => Ord1 (ConstF e f :: Type -> Type) Source # | |||||
Defined in Data.HFunctor | |||||
| Read e => Read1 (ConstF e f :: Type -> Type) Source # | |||||
Defined in Data.HFunctor Methods liftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (ConstF e f a) # liftReadList :: (Int -> ReadS a) -> ReadS [a] -> ReadS [ConstF e f a] # liftReadPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec (ConstF e f a) # liftReadListPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec [ConstF e f a] # | |||||
| Show e => Show1 (ConstF e f :: Type -> Type) Source # | |||||
| Contravariant (ConstF e f :: Type -> Type) Source # | Since: 0.3.0.0 | ||||
| Traversable (ConstF e f :: Type -> Type) Source # | |||||
Defined in Data.HFunctor | |||||
| Functor (ConstF e f :: Type -> Type) Source # | |||||
| Monoid e => Divisible (ConstF e f :: Type -> Type) Source # | Since: 0.3.0.0 | ||||
| Semigroup e => Divise (ConstF e f :: Type -> Type) Source # | Since: 0.3.0.0 | ||||
| Invariant (ConstF e f :: Type -> Type) Source # | Since: 0.3.0.0 | ||||
Defined in Data.HFunctor | |||||
| (Typeable f, Typeable a, Typeable k1, Typeable k2, Data e) => Data (ConstF e f a) Source # | |||||
Defined in Data.HFunctor Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> ConstF e f a -> c (ConstF e f a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (ConstF e f a) # toConstr :: ConstF e f a -> Constr # dataTypeOf :: ConstF e f a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (ConstF e f a)) # dataCast2 :: Typeable t => (forall d e0. (Data d, Data e0) => c (t d e0)) -> Maybe (c (ConstF e f a)) # gmapT :: (forall b. Data b => b -> b) -> ConstF e f a -> ConstF e f a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ConstF e f a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ConstF e f a -> r # gmapQ :: (forall d. Data d => d -> u) -> ConstF e f a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> ConstF e f a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> ConstF e f a -> m (ConstF e f a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> ConstF e f a -> m (ConstF e f a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> ConstF e f a -> m (ConstF e f a) # | |||||
| Generic (ConstF e f a) Source # | |||||
Defined in Data.HFunctor Associated Types
| |||||
| Read e => Read (ConstF e f a) Source # | |||||
| Show e => Show (ConstF e f a) Source # | |||||
| Eq e => Eq (ConstF e f a) Source # | |||||
| Ord e => Ord (ConstF e f a) Source # | |||||
Defined in Data.HFunctor | |||||
| type Rep (ConstF e f a) Source # | |||||
Defined in Data.HFunctor | |||||
HFunctor Combinators
data HLift (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (a :: k) Source #
An "HFunctor combinator" that enhances an HFunctor with the ability to hold a single f a. This is the higher-order analogue of Lift.
You can think of it as a free Inject for any f.
Instances
| HTraversable t => HTraversable (HLift t :: (k1 -> Type) -> k1 -> Type) Source # | |
Defined in Data.HFunctor.HTraversable | |
| HTraversable1 t => HTraversable1 (HLift t :: (k1 -> Type) -> k1 -> Type) Source # | |
Defined in Data.HFunctor.HTraversable | |
| HFunctor t => HFunctor (HLift t :: (k1 -> Type) -> k1 -> Type) Source # | |
| HBind t => HBind (HLift t :: (k -> Type) -> k -> Type) Source # | |
| HFunctor t => Inject (HLift t :: (k -> Type) -> k -> Type) Source # | |
| Interpret t f => Interpret (HLift t :: (k -> Type) -> k -> Type) (f :: k -> Type) Source # | Never uses |
| (Eq1 (t f), Eq1 f) => Eq1 (HLift t f) Source # | |
| (Ord1 (t f), Ord1 f) => Ord1 (HLift t f) Source # | |
Defined in Data.HFunctor | |
| (Show1 (t f), Show1 f) => Show1 (HLift t f) Source # | |
| (Contravariant f, Contravariant (t f)) => Contravariant (HLift t f) Source # | Since: 0.3.0.0 |
| (Functor f, Functor (t f)) => Functor (HLift t f) Source # | |
| (Invariant f, Invariant (t f)) => Invariant (HLift t f) Source # | Since: 0.3.0.0 |
Defined in Data.HFunctor | |
| (Read (f a), Read (t f a)) => Read (HLift t f a) Source # | |
| (Show (f a), Show (t f a)) => Show (HLift t f a) Source # | |
| (Eq (f a), Eq (t f a)) => Eq (HLift t f a) Source # | |
| (Ord (f a), Ord (t f a)) => Ord (HLift t f a) Source # | |
Defined in Data.HFunctor | |
data HFree (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (a :: k) Source #
An "HFunctor combinator" that turns an HFunctor into potentially infinite nestings of that HFunctor.
An is either HFree t f af a, t f a, t (t f) a, t (t (t f)) a, etc.
This effectively turns t into a tree with t branches.
One particularly useful usage is with MapF. For example if you had a data type representing a command line command parser:
data Command a
You could represent "many possible named commands" using
type Commands =MapFStringCommand
And you can represent multiple nested named commands using:
type NestedCommands =HFree(MapFString)
This has an Interpret instance, but it can be more useful to use via direct pattern matching, or through
foldHFree::HBifunctort => f~>g -> t g ~> g -> HFree t f ~> g
which requires no extra constriant on g, and lets you consider each branch separately.
This can be considered the higher-oder analogue of Free; it is the free HBind for any .HFunctor t
Instances
| HTraversable t => HTraversable (HFree t :: (k1 -> Type) -> k1 -> Type) Source # | |
Defined in Data.HFunctor.HTraversable | |
| HTraversable1 t => HTraversable1 (HFree t :: (k1 -> Type) -> k1 -> Type) Source # | |
Defined in Data.HFunctor.HTraversable | |
| HFunctor t => HFunctor (HFree t :: (k1 -> Type) -> k1 -> Type) Source # | |
| HFunctor t => HBind (HFree t :: (k -> Type) -> k -> Type) Source # | |
| HFunctor t => Inject (HFree t :: (k -> Type) -> k -> Type) Source # | |
| Interpret t f => Interpret (HFree t :: (k -> Type) -> k -> Type) (f :: k -> Type) Source # | Never uses |
| (Show1 (t (HFree t f)), Show1 f) => Show1 (HFree t f) Source # | |
| (Contravariant f, Contravariant (t (HFree t f))) => Contravariant (HFree t f) Source # | |
| (Functor f, Functor (t (HFree t f))) => Functor (HFree t f) Source # | |
| (Invariant f, Invariant (t (HFree t f))) => Invariant (HFree t f) Source # | |
Defined in Data.HFunctor | |
| (Show1 (t (HFree t f)), Show1 f, Show a) => Show (HFree t f a) Source # | |
foldHFree :: forall {k} (t :: (k -> Type) -> k -> Type) (f :: k -> Type) (g :: k -> Type). HFunctor t => (f ~> g) -> (t g ~> g) -> HFree t f ~> g Source #
Utility functions
injectMap :: (Inject t, Functor f) => (a -> b) -> f a -> t f b Source #
A useful wrapper over the common pattern of fmap-before-inject/inject-and-fmap.
Since: 0.3.3.0
injectContramap :: (Inject t, Contravariant f) => (a -> b) -> f b -> t f a Source #
A useful wrapper over the common pattern of contramap-before-inject/inject-and-contramap.
Since: 0.3.3.0