kindly-functors-0.1.0.0: src/Kindly/Functor.hs
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Single Parameter Functors of arbitrary categories.
module Kindly.Functor
( Functor,
fmap,
contramap,
invmap,
Filterable,
mapMaybe,
catMaybes,
filter,
)
where
--------------------------------------------------------------------------------
import Control.Applicative (Const, WrappedArrow, WrappedMonad, ZipList)
import Control.Arrow (Arrow, ArrowMonad, Kleisli (..))
import Control.Category (Category (..))
import Control.Exception (Handler)
import Control.Monad (Monad)
import Control.Monad.ST (ST)
import Control.Monad.ST.Lazy qualified as Lazy
import Data.Complex (Complex)
import Data.Either (Either)
import Data.Functor qualified as Hask
import Data.Functor.Compose (Compose (..))
import Data.Functor.Contravariant (Op (..), Predicate)
import Data.Functor.Contravariant qualified as Hask
import Data.Functor.Identity (Identity (..))
import Data.Functor.Product (Product (..))
import Data.Functor.Sum (Sum (..))
import Data.Kind (Constraint, Type)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (Maybe (..))
import Data.Monoid qualified as Monoid
import Data.Ord (Down)
import Data.Profunctor qualified as Hask.Profunctor
import Data.Proxy (Proxy)
import Data.Semigroup qualified as Semigroup
import Data.These (These)
import Data.Tuple (Solo)
import Foreign (Ptr)
import GHC.Arr (Array)
import GHC.Base (Char, Double, IO, Int, Word, ($))
import GHC.Conc (STM)
import GHC.Exts (Float)
import GHC.Generics (K1, M1 (..), Par1, Rec1 (..), U1, URec, V1, (:*:) (..), (:+:) (..), (:.:) (..))
import Kindly.Class
import Kindly.Iso
import System.Console.GetOpt (ArgDescr, ArgOrder, OptDescr)
import Text.ParserCombinators.ReadP (ReadP)
import Text.ParserCombinators.ReadPrec (ReadPrec)
import Witherable qualified as Hask
import Prelude (Bool)
--------------------------------------------------------------------------------
-- | A 'CategoricalFunctor' of kind @Type -> Type@ mapping from an
-- arbitrary category @cat@ to @->@.
type Functor :: (Type -> Type -> Type) -> (Type -> Type) -> Constraint
type Functor cat p = (MapArg1 cat p)
-- | Lift a function @cat a b@ into a function @f a -> f b@.
fmap :: forall cat f. (Functor cat f) => forall a b. (a `cat` b) -> f a -> f b
fmap = map1
-- | A specialization of 'fmap' for contravariant functors as defined
-- in 'Data.Functor.Contravariant.'
--
-- TODO: Do we keep this around? This is nice to have so that library
-- users don't have to manually pack functions in 'Op'.
contramap :: (Functor Op p) => (a -> b) -> p b -> p a
contramap = fmap . Op
-- | A specialization of 'fmap' for invariant functors as defined
-- in 'Data.Functor.Invariant.'
--
-- TODO: Do we keep this around? This is nice to have so that library
-- users don't have to manually pack functions in 'Iso'.
invmap :: (Functor (<->) f) => (a -> b) -> (b -> a) -> f a -> f b
invmap f g = fmap (Iso f g)
-- TODO: 'Filterable' is currently unusable due to fundeps. This can
-- be fixed by making it @FunctorOf (Hask.Star Maybe) (->) p@, but I
-- think we can do better by switching away from associated types.
type Filterable p = Functor (Hask.Profunctor.Star Maybe) p
-- | A specialization of 'fmap' for filterable functors as defined
-- in 'Witherable'
--
-- TODO: Do we keep this around? This is nice to have so that library
-- users don't have to manually pack functions in 'Hask.Star'.
mapMaybe :: (Filterable f) => (a -> Maybe b) -> f a -> f b
mapMaybe f = map (Hask.Profunctor.Star f)
-- | The 'catMaybes' function takes a list of 'Maybe's and returns
-- a list of all the 'Just' values.
--
-- TODO: Do we keep this around? This is nice to have so that library
-- users don't have to manually pack functions in 'Hask.Star'.
catMaybes :: (Filterable f) => f (Maybe a) -> f a
catMaybes = map (Hask.Profunctor.Star id)
-- | Applied to a predicate and a functor @f a@, returns the those
-- elements that satisfy the predicate.
--
-- TODO: Do we keep this around? This is nice to have so that library
-- users don't have to manually pack functions in 'Hask.Star'.
filter :: (Filterable f) => (a -> Bool) -> f a -> f a
filter f = map (Hask.Profunctor.Star (\a -> if f a then Just a else Nothing))
--------------------------------------------------------------------------------
newtype FromFunctor f a = FromFunctor (f a)
deriving newtype (Hask.Functor)
instance (Hask.Functor f) => CategoricalFunctor (FromFunctor f) where
type Dom (FromFunctor f) = (->)
type Cod (FromFunctor f) = (->)
map :: (a -> b) -> FromFunctor f a -> FromFunctor f b
map = Hask.fmap
--------------------------------------------------------------------------------
-- Covariant Functor instances
deriving via (FromFunctor ZipList) instance CategoricalFunctor ZipList
deriving via (FromFunctor Handler) instance CategoricalFunctor Handler
deriving via (FromFunctor Complex) instance CategoricalFunctor Complex
deriving via (FromFunctor Identity) instance CategoricalFunctor Identity
deriving via (FromFunctor Monoid.First) instance CategoricalFunctor Monoid.First
deriving via (FromFunctor Monoid.Last) instance CategoricalFunctor Monoid.Last
deriving via (FromFunctor Down) instance CategoricalFunctor Down
deriving via (FromFunctor Semigroup.First) instance CategoricalFunctor Semigroup.First
deriving via (FromFunctor Semigroup.Last) instance CategoricalFunctor Semigroup.Last
deriving via (FromFunctor Semigroup.Max) instance CategoricalFunctor Semigroup.Max
deriving via (FromFunctor Semigroup.Min) instance CategoricalFunctor Semigroup.Min
deriving via (FromFunctor Semigroup.Dual) instance CategoricalFunctor Semigroup.Dual
deriving via (FromFunctor Semigroup.Product) instance CategoricalFunctor Semigroup.Product
deriving via (FromFunctor Semigroup.Sum) instance CategoricalFunctor Semigroup.Sum
deriving via (FromFunctor NonEmpty) instance CategoricalFunctor NonEmpty
deriving via (FromFunctor STM) instance CategoricalFunctor STM
deriving via (FromFunctor Par1) instance CategoricalFunctor Par1
deriving via (FromFunctor ArgDescr) instance CategoricalFunctor ArgDescr
deriving via (FromFunctor ArgOrder) instance CategoricalFunctor ArgOrder
deriving via (FromFunctor OptDescr) instance CategoricalFunctor OptDescr
deriving via (FromFunctor ReadP) instance CategoricalFunctor ReadP
deriving via (FromFunctor ReadPrec) instance CategoricalFunctor ReadPrec
deriving via (FromFunctor IO) instance CategoricalFunctor IO
deriving via (FromFunctor Maybe) instance CategoricalFunctor Maybe
deriving via (FromFunctor Solo) instance CategoricalFunctor Solo
deriving via (FromFunctor []) instance CategoricalFunctor []
deriving via (FromFunctor (WrappedMonad m)) instance (Monad m) => CategoricalFunctor (WrappedMonad m)
deriving via (FromFunctor (ArrowMonad a)) instance (Arrow a) => CategoricalFunctor (ArrowMonad a)
deriving via (FromFunctor (Lazy.ST s)) instance CategoricalFunctor (Lazy.ST s)
deriving via (FromFunctor (Either a)) instance CategoricalFunctor (Either a)
deriving via (FromFunctor (These a)) instance CategoricalFunctor (These a)
deriving via (FromFunctor Proxy) instance CategoricalFunctor (Proxy :: Type -> Type)
deriving via (FromFunctor (Semigroup.Arg a)) instance CategoricalFunctor (Semigroup.Arg a)
deriving via (FromFunctor (Array i)) instance CategoricalFunctor (Array i)
deriving via (FromFunctor U1) instance CategoricalFunctor (U1 :: Type -> Type)
deriving via (FromFunctor V1) instance CategoricalFunctor (V1 :: Type -> Type)
deriving via (FromFunctor (ST s)) instance CategoricalFunctor (ST s)
deriving via (FromFunctor ((,) a)) instance CategoricalFunctor ((,) a)
deriving via (FromFunctor (WrappedArrow a b)) instance (Arrow a) => CategoricalFunctor (WrappedArrow a b)
-- TODO: Figure out if these instances be written with Deriving Via.
instance (FunctorOf (->) (->) m) => CategoricalFunctor (Kleisli m a) where
type Dom (Kleisli m a) = (->)
type Cod (Kleisli m a) = (->)
map :: (a1 -> b) -> Kleisli m a a1 -> Kleisli m a b
map f (Kleisli m) = Kleisli $ \a -> map f (m a)
deriving via (FromFunctor (Const m)) instance CategoricalFunctor (Const m :: Type -> Type)
instance (FunctorOf (->) (->) f) => CategoricalFunctor (Monoid.Ap f) where
type Dom (Monoid.Ap f) = (->)
type Cod (Monoid.Ap f) = (->)
map f (Monoid.Ap m) = Monoid.Ap $ map f m
instance (FunctorOf (->) (->) f) => CategoricalFunctor (Monoid.Alt f) where
type Dom (Monoid.Alt f) = (->)
type Cod (Monoid.Alt f) = (->)
map f (Monoid.Alt m) = Monoid.Alt $ map f m
instance (FunctorOf (->) (->) f) => CategoricalFunctor (Rec1 f) where
type Dom (Rec1 f) = (->)
type Cod (Rec1 f) = (->)
map f (Rec1 m) = Rec1 $ map f m
deriving via (FromFunctor (URec (Ptr ()))) instance CategoricalFunctor (URec (Ptr ()) :: Type -> Type)
deriving via (FromFunctor (URec Char)) instance CategoricalFunctor (URec Char :: Type -> Type)
deriving via (FromFunctor (URec Double)) instance CategoricalFunctor (URec Double :: Type -> Type)
deriving via (FromFunctor (URec Float)) instance CategoricalFunctor (URec Float :: Type -> Type)
deriving via (FromFunctor (URec Int)) instance CategoricalFunctor (URec Int :: Type -> Type)
deriving via (FromFunctor (URec Word)) instance CategoricalFunctor (URec Word :: Type -> Type)
deriving via (FromFunctor ((,,) a b)) instance CategoricalFunctor ((,,) a b)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (Product f g) where
type Dom (Product f g) = (->)
type Cod (Product f g) = (->)
map f (Pair m1 m2) = Pair (map f m1) (map f m2)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (Sum f g) where
type Dom (Sum f g) = (->)
type Cod (Sum f g) = (->)
map f (InL m1) = InL $ map f m1
map f (InR m2) = InR $ map f m2
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (f :*: g) where
type Dom (f :*: g) = (->)
type Cod (f :*: g) = (->)
map f (m1 :*: m2) = map f m1 :*: map f m2
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (f :+: g) where
type Dom (f :+: g) = (->)
type Cod (f :+: g) = (->)
map f (L1 m1) = L1 $ map f m1
map f (R1 m2) = R1 $ map f m2
deriving via (FromFunctor (K1 i c)) instance CategoricalFunctor (K1 i c :: Type -> Type)
deriving via (FromFunctor ((,,,) a b c)) instance CategoricalFunctor ((,,,) a b c)
deriving via (FromFunctor ((->) r)) instance CategoricalFunctor ((->) r)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (Compose f g) where
type Dom (Compose f g) = (->)
type Cod (Compose f g) = (->)
map f (Compose fga) = Compose $ map (map f) fga
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => CategoricalFunctor (f :.: g) where
type Dom (f :.: g) = (->)
type Cod (f :.: g) = (->)
map f (Comp1 fga) = Comp1 $ map (map f) fga
instance (FunctorOf (->) (->) f) => CategoricalFunctor (M1 i c f) where
type Dom (M1 i c f) = (->)
type Cod (M1 i c f) = (->)
map f (M1 fp) = M1 $ map f fp
deriving via (FromFunctor ((,,,,) a b c d)) instance CategoricalFunctor ((,,,,) a b c d)
deriving via (FromFunctor ((,,,,,) a b c d e)) instance CategoricalFunctor ((,,,,,) a b c d e)
deriving via (FromFunctor ((,,,,,,) a b c d e f)) instance CategoricalFunctor ((,,,,,,) a b c d e f)
--------------------------------------------------------------------------------
-- Covariant MapArg1 instances
instance MapArg1 (->) ZipList
instance MapArg1 (->) Handler
instance MapArg1 (->) Complex
instance MapArg1 (->) Identity
instance MapArg1 (->) Monoid.First
instance MapArg1 (->) Monoid.Last
instance MapArg1 (->) Down
instance MapArg1 (->) Semigroup.First
instance MapArg1 (->) Semigroup.Last
instance MapArg1 (->) Semigroup.Max
instance MapArg1 (->) Semigroup.Min
instance MapArg1 (->) Semigroup.Dual
instance MapArg1 (->) Semigroup.Product
instance MapArg1 (->) Semigroup.Sum
instance MapArg1 (->) NonEmpty
instance MapArg1 (->) STM
instance MapArg1 (->) Par1
instance MapArg1 (->) ArgDescr
instance MapArg1 (->) ArgOrder
instance MapArg1 (->) OptDescr
instance MapArg1 (->) ReadP
instance MapArg1 (->) ReadPrec
instance MapArg1 (->) IO
instance MapArg1 (->) Maybe
instance MapArg1 (->) Solo
instance MapArg1 (->) []
instance (Monad m) => MapArg1 (->) (WrappedMonad m)
instance (Arrow a) => MapArg1 (->) (ArrowMonad a)
instance MapArg1 (->) (Lazy.ST s)
instance MapArg1 (->) (Either a)
instance MapArg1 (->) (Proxy :: Type -> Type)
instance MapArg1 (->) (Semigroup.Arg a)
instance MapArg1 (->) (Array i)
instance MapArg1 (->) (U1 :: Type -> Type)
instance MapArg1 (->) (V1 :: Type -> Type)
instance MapArg1 (->) (ST s)
instance MapArg1 (->) ((,) a)
instance (Arrow a) => MapArg1 (->) (WrappedArrow a b)
instance (FunctorOf (->) (->) m) => MapArg1 (->) (Kleisli m a)
instance MapArg1 (->) (Const m :: Type -> Type)
instance (FunctorOf (->) (->) f) => MapArg1 (->) (Monoid.Ap f)
instance (FunctorOf (->) (->) f) => MapArg1 (->) (Monoid.Alt f)
instance (FunctorOf (->) (->) f) => MapArg1 (->) (Rec1 f)
instance MapArg1 (->) (URec (Ptr ()) :: Type -> Type)
instance MapArg1 (->) (URec Char :: Type -> Type)
instance MapArg1 (->) (URec Double :: Type -> Type)
instance MapArg1 (->) (URec Float :: Type -> Type)
instance MapArg1 (->) (URec Int :: Type -> Type)
instance MapArg1 (->) (URec Word :: Type -> Type)
instance MapArg1 (->) ((,,) a b)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (Product f g)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (Sum f g)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (f :*: g)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (f :+: g)
instance MapArg1 (->) (K1 i c :: Type -> Type)
instance MapArg1 (->) ((,,,) a b c)
instance MapArg1 (->) ((->) r)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (Compose f g)
instance (FunctorOf (->) (->) f, FunctorOf (->) (->) g) => MapArg1 (->) (f :.: g)
instance (FunctorOf (->) (->) f) => MapArg1 (->) (M1 i c f)
instance MapArg1 (->) ((,,,,) a b c d)
instance MapArg1 (->) ((,,,,,) a b c d e)
instance MapArg1 (->) ((,,,,,,) a b c d e f)
--------------------------------------------------------------------------------
newtype FromContra f a = FromContra (f a)
deriving newtype (Hask.Contravariant)
instance (Hask.Contravariant f) => CategoricalFunctor (FromContra f) where
type Dom (FromContra f) = Op
type Cod (FromContra f) = (->)
map :: Dom (FromContra f) a b -> Cod (FromContra f) ((FromContra f) a) ((FromContra f) b)
map = Hask.contramap . getOp
--------------------------------------------------------------------------------
-- Contravariant Functor instances
deriving via (FromContra Predicate) instance CategoricalFunctor Predicate
-- TODO: Add remaining Contravariant instances
--------------------------------------------------------------------------------
-- Contravariant MapArg1 instances
instance MapArg1 Op Predicate
-- TODO: Add remaining Contravariant instances
--------------------------------------------------------------------------------
instance CategoricalFunctor Monoid.Endo where
type Dom Monoid.Endo = (<->)
type Cod Monoid.Endo = (->)
map :: (a <-> b) -> Monoid.Endo a -> Monoid.Endo b
map Iso {..} (Monoid.Endo f) = Monoid.Endo (fwd . f . bwd)
instance MapArg1 (<->) Monoid.Endo
--------------------------------------------------------------------------------
newtype FromFilterable f a = FromFilterable (f a)
deriving newtype (Hask.Functor, Hask.Filterable)
instance (Hask.Filterable f) => CategoricalFunctor (FromFilterable f) where
type Dom (FromFilterable f) = (Hask.Profunctor.Star Maybe)
type Cod (FromFilterable f) = (->)
map :: Hask.Profunctor.Star Maybe a b -> FromFilterable f a -> FromFilterable f b
map (Hask.Profunctor.Star f) (FromFilterable fa) = FromFilterable (Hask.mapMaybe f fa)
--------------------------------------------------------------------------------
-- NOTE: These instances conflict with our Covariant Functor
-- instances. Switching from associated types to Multi Parameter type
-- classes would fix this:
-- deriving via (FromFilterable []) instance Functor []
-- deriving via (FromFilterable Maybe) instance Functor Maybe