{-# LANGUAGE CPP, DerivingVia, GADTs, InstanceSigs, KindSignatures #-} {-# LANGUAGE PatternSynonyms, RankNTypes, RoleAnnotations #-} {-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, TemplateHaskell #-} {-# LANGUAGE TypeApplications, TypeFamilies, TypeOperators #-} {-# LANGUAGE UndecidableSuperClasses #-} {-# OPTIONS_GHC -Wno-orphans #-} module Control.Subcategory.Functor ( Constrained(..), Dom(), CFunctor (..), (<$:>), defaultCmapConst, WrapFunctor (..), WrapMono (WrapMono, unwrapMono), coerceToMono, withMonoCoercible, ) where import qualified Control.Applicative as App import Control.Arrow (Arrow, ArrowMonad) import Control.Exception (Handler) import qualified Control.Monad.ST.Lazy as LST import qualified Control.Monad.ST.Strict as SST import Control.Subcategory.Wrapper.Internal import Data.Coerce import Data.Complex (Complex) import qualified Data.Functor.Compose as SOP import Data.Functor.Const (Const) import Data.Functor.Identity (Identity) import qualified Data.Functor.Product as SOP import qualified Data.Functor.Sum as SOP import Data.Hashable (Hashable) import qualified Data.HashMap.Strict as HM import qualified Data.HashSet as HS import qualified Data.IntMap as IM import Data.Kind (Constraint, Type) import Data.List.NonEmpty (NonEmpty) import qualified Data.Map as Map import qualified Data.Monoid as Mon import Data.MonoTraversable (Element, MonoFunctor (..)) #if MIN_VERSION_mono_traversable(1,0,14) import Data.MonoTraversable (WrappedMono) #endif import qualified Data.IntSet as IS import Data.Ord (Down (..)) import qualified Data.Primitive.Array as A import qualified Data.Primitive.PrimArray as PA import qualified Data.Primitive.SmallArray as SA import Data.Proxy (Proxy) import qualified Data.Semigroup as Sem import qualified Data.Sequence as Seq import qualified Data.Set as Set import qualified Data.Tree as Tree import qualified Data.Vector as V import qualified Data.Vector.Primitive as P import qualified Data.Vector.Storable as S import qualified Data.Vector.Unboxed as U import Foreign.Ptr (Ptr) import GHC.Conc (STM) import GHC.Generics ((:*:) (..), (:+:) (..), (:.:) (..), K1, M1, Par1, Rec1, U1, URec, V1) import qualified System.Console.GetOpt as GetOpt import Text.ParserCombinators.ReadP (ReadP) import Text.ParserCombinators.ReadPrec (ReadPrec) infixl 4 <$: class Constrained (f :: Type -> Type) where type Dom f (a :: Type) :: Constraint type Dom f a = () class Constrained f => CFunctor f where cmap :: (Dom f a, Dom f b) => (a -> b) -> f a -> f b default cmap :: Functor f => (a -> b) -> f a -> f b cmap = fmap {-# INLINE cmap #-} (<$:) :: (Dom f a, Dom f b) => a -> f b -> f a (<$:) = cmap . const {-# INLINE (<$:) #-} defaultCmapConst :: (CFunctor f, Dom f a, Dom f b) => a -> f b -> f a defaultCmapConst = cmap . const {-# INLINE defaultCmapConst #-} instance Constrained (WrapFunctor f) where type Dom (WrapFunctor f) a = () instance Functor f => CFunctor (WrapFunctor f) where cmap :: (a -> b) -> WrapFunctor f a -> WrapFunctor f b cmap = fmap {-# INLINE cmap #-} (<$:) :: a -> WrapFunctor f b -> WrapFunctor f a (<$:) = (<$) {-# INLINE (<$:) #-} instance Constrained [] instance CFunctor [] instance Constrained Maybe instance CFunctor Maybe instance Constrained IO instance CFunctor IO instance Constrained Par1 instance CFunctor Par1 instance Constrained NonEmpty instance CFunctor NonEmpty instance Constrained ReadP instance CFunctor ReadP instance Constrained ReadPrec instance CFunctor ReadPrec instance Constrained Down instance CFunctor Down instance Constrained Mon.Product instance CFunctor Mon.Product instance Constrained Mon.Sum instance CFunctor Mon.Sum instance Constrained Mon.Dual instance CFunctor Mon.Dual instance Constrained Mon.Last instance CFunctor Mon.Last instance Constrained Mon.First instance CFunctor Mon.First instance Constrained STM instance CFunctor STM instance Constrained Handler instance CFunctor Handler instance Constrained Identity instance CFunctor Identity instance Constrained App.ZipList instance CFunctor App.ZipList instance Constrained GetOpt.ArgDescr instance CFunctor GetOpt.ArgDescr instance Constrained GetOpt.OptDescr instance CFunctor GetOpt.OptDescr instance Constrained GetOpt.ArgOrder instance CFunctor GetOpt.ArgOrder instance Constrained Sem.Option instance CFunctor Sem.Option instance Constrained Sem.Last instance CFunctor Sem.Last instance Constrained Sem.First instance CFunctor Sem.First instance Constrained Sem.Max instance CFunctor Sem.Max instance Constrained Sem.Min instance CFunctor Sem.Min instance Constrained Complex instance CFunctor Complex instance Constrained (Either a) instance CFunctor (Either a) instance Constrained V1 instance CFunctor V1 instance Constrained U1 instance CFunctor U1 instance Constrained ((,) a) instance CFunctor ((,) a) instance Constrained (SST.ST s) instance CFunctor (SST.ST s) instance Constrained (LST.ST s) instance CFunctor (LST.ST s) instance Constrained Proxy instance CFunctor Proxy instance Constrained (ArrowMonad a) instance Arrow a => CFunctor (ArrowMonad a) instance Constrained (App.WrappedMonad m) instance Monad m => CFunctor (App.WrappedMonad m) instance Constrained (Sem.Arg a) instance CFunctor (Sem.Arg a) instance Constrained (Rec1 f) instance Functor f => CFunctor (Rec1 f) instance Constrained (URec Char) instance CFunctor (URec Char) instance Constrained (URec Double) instance CFunctor (URec Double) instance Constrained (URec Float) instance CFunctor (URec Float) instance Constrained (URec Int) instance CFunctor (URec Int) instance Constrained (URec Word) instance CFunctor (URec Word) instance Constrained (URec (Ptr ())) instance CFunctor (URec (Ptr ())) instance Constrained f => Constrained (Mon.Ap f) where type Dom (Mon.Ap f) a = Dom f a deriving newtype instance CFunctor f => CFunctor (Mon.Ap f) instance Constrained (Mon.Alt f) where type Dom (Mon.Alt f) a = Dom f a deriving newtype instance CFunctor f => CFunctor (Mon.Alt f) instance Constrained (Const m) instance CFunctor (Const m) instance Constrained (App.WrappedArrow a b) instance Arrow a => CFunctor (App.WrappedArrow a b) instance Constrained ((->) r) instance CFunctor ((->) r) instance Constrained (K1 i c) instance CFunctor (K1 i c) instance Constrained (f :+: g) where type Dom (f :+: g) a = (Dom f a, Dom g a) instance (CFunctor f, CFunctor g) => CFunctor (f :+: g) where cmap f (L1 xs) = L1 $ cmap f xs cmap f (R1 xs) = R1 $ cmap f xs {-# INLINE [1] cmap #-} instance Constrained (f :*: g) where type Dom (f :*: g) a = (Dom f a, Dom g a) instance (CFunctor f, CFunctor g) => CFunctor (f :*: g) where cmap f (l :*: r) = cmap f l :*: cmap f r {-# INLINE cmap #-} instance Constrained (f :.: (g :: Type -> Type)) where type Dom (f :.: g) a = (Dom f (g a), Dom g a) instance (CFunctor f, CFunctor g) => CFunctor (f :.: g) where cmap f gfa = Comp1 $ cmap (cmap f) $ unComp1 gfa {-# INLINE cmap #-} instance (Constrained f, Constrained g) => Constrained (SOP.Sum f g) where type Dom (SOP.Sum f g) a = (Dom f a, Dom g a) instance (CFunctor f, CFunctor g) => CFunctor (SOP.Sum f g) where cmap f (SOP.InL a) = SOP.InL $ cmap f a cmap f (SOP.InR b) = SOP.InR $ cmap f b {-# INLINE cmap #-} (<$:) = defaultCmapConst {-# INLINE (<$:) #-} instance (Constrained f, Constrained g) => Constrained (SOP.Product f g) where type Dom (SOP.Product f g) a = (Dom f a, Dom g a) instance (CFunctor f, CFunctor g) => CFunctor (SOP.Product f g) where cmap f (SOP.Pair a b) = SOP.Pair (cmap f a) (cmap f b) {-# INLINE cmap #-} (<$:) = defaultCmapConst {-# INLINE (<$:) #-} instance (Constrained (f ::Type -> Type), Constrained (g :: Type -> Type)) => Constrained (SOP.Compose f g) where type Dom (SOP.Compose f g) a = (Dom g a, Dom f (g a)) instance (CFunctor f, CFunctor g) => CFunctor (SOP.Compose f g) where cmap f (SOP.Compose a) = SOP.Compose $ cmap (cmap f) a (<$:) = defaultCmapConst {-# INLINE (<$:) #-} instance Constrained (M1 i c f) instance Functor f => CFunctor (M1 i c f) instance Constrained Seq.Seq instance CFunctor Seq.Seq #if MIN_VERSION_mono_traversable(1,0,14) instance Constrained (WrappedMono mono) where type Dom (WrappedMono mono) a = a ~ Element mono instance MonoFunctor IS.IntSet where omap = IS.map instance MonoFunctor mono => CFunctor (WrappedMono mono) where cmap = omap (<$:) = omap . const #endif instance Constrained (WrapMono mono) where type Dom (WrapMono mono) b = b ~ Element mono instance {-# OVERLAPPABLE #-} MonoFunctor a => CFunctor (WrapMono a) where cmap = coerce @((Element a -> Element a) -> a -> a) omap {-# INLINE [1] cmap #-} (<$:) = defaultCmapConst {-# INLINE [1] (<$:) #-} instance Constrained IM.IntMap instance CFunctor IM.IntMap instance Constrained (Map.Map k) instance Ord k => CFunctor (Map.Map k) instance Constrained Set.Set where type Dom Set.Set a = Ord a instance CFunctor Set.Set where cmap = Set.map {-# INLINE [1] cmap #-} (<$:) = flip $ \s -> if Set.null s then const Set.empty else Set.singleton {-# INLINE [1] (<$:) #-} instance Constrained HS.HashSet where type Dom HS.HashSet a = (Hashable a, Eq a) instance CFunctor HS.HashSet where cmap :: (Hashable b, Eq b) => (a -> b) -> HS.HashSet a -> HS.HashSet b cmap = HS.map {-# INLINE [1] cmap #-} (<$:) = flip $ \s -> if HS.null s then const HS.empty else HS.singleton {-# INLINE (<$:) #-} instance Constrained (HM.HashMap k) instance CFunctor (HM.HashMap k) instance Constrained Tree.Tree instance CFunctor Tree.Tree infixl 4 <$:> (<$:>) :: (CFunctor f, Dom f a, Dom f b) => (a -> b) -> f a -> f b (<$:>) = cmap {-# INLINE [1] (<$:>) #-} instance Constrained V.Vector where type Dom V.Vector a = () instance CFunctor V.Vector where cmap = V.map {-# INLINE [1] cmap #-} instance Constrained U.Vector where type Dom U.Vector a = U.Unbox a instance CFunctor U.Vector where cmap = U.map {-# INLINE [1] cmap #-} instance Constrained S.Vector where type Dom S.Vector a = S.Storable a instance CFunctor S.Vector where cmap = S.map {-# INLINE [1] cmap #-} instance Constrained P.Vector where type Dom P.Vector a = P.Prim a instance CFunctor P.Vector where cmap = P.map {-# INLINE [1] cmap #-} instance Constrained PA.PrimArray where type Dom PA.PrimArray a = P.Prim a instance CFunctor PA.PrimArray where cmap = PA.mapPrimArray {-# INLINE [1] cmap #-} deriving via WrapFunctor SA.SmallArray instance Constrained SA.SmallArray deriving via WrapFunctor SA.SmallArray instance CFunctor SA.SmallArray deriving via WrapFunctor A.Array instance Constrained A.Array deriving via WrapFunctor A.Array instance CFunctor A.Array