-- | -- Module : Control.Functor.Constrained -- Copyright : (c) 2014 Justus Sagemüller -- License : GPL v3 (see COPYING) -- Maintainer : (@) sagemueller $ geo.uni-koeln.de -- {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# LANGUAGE UndecidableSuperClasses #-} #endif module Control.Functor.Constrained ( module Control.Category.Constrained -- * Functors , Functor(..) , (<$>) , constrainedFmap -- * [Co]product mapping , SumToProduct(..) ) where import Control.Category.Constrained import Prelude hiding (id, (.), Functor(..), filter, (<$>)) import qualified Prelude import Data.Void import Data.Type.Coercion import Data.Complex import Control.Category.Discrete class ( Category r, Category t, Object t (f (UnitObject r)) ) => Functor f r t | f r -> t, f t -> r where fmap :: (Object r a, Object t (f a), Object r b, Object t (f b)) => r a b -> t (f a) (f b) instance (Prelude.Functor f) => Functor f (->) (->) where fmap = Prelude.fmap -- | It is fairly common for functors (typically, container-like) to map 'Either' -- to tuples in a natural way, thus \"separating the variants\". -- This is related to 'Data.Foldable.Constrained.Foldable' -- (with list and tuple monoids), but rather more effective. class ( CoCartesian r, Cartesian t, Functor f r t, Object t (f (ZeroObject r)) ) => SumToProduct f r t where -- | @ -- sum2product ≡ mapEither id -- @ sum2product :: ( ObjectSum r a b, ObjectPair t (f a) (f b) ) => t (f (a+b)) (f a, f b) -- | @ -- mapEither f ≡ sum2product . fmap f -- @ mapEither :: ( Object r a, ObjectSum r b c , Object t (f a), ObjectPair t (f b) (f c) ) => r a (b+c) -> t (f a) (f b, f c) filter :: ( Object r a, Object r Bool, Object t (f a) ) => r a Bool -> t (f a) (f a) instance SumToProduct [] (->) (->) where sum2product [] = ([],[]) sum2product (Left x : l) = (x:xs, ys) where ~(xs,ys) = sum2product l sum2product (Right y : l) = (xs ,y:ys) where ~(xs,ys) = sum2product l mapEither _ [] = ([],[]) mapEither f (a:l) = case f a of Left x -> (x:xs, ys) Right y -> (xs ,y:ys) where ~(xs,ys) = mapEither f l filter = Prelude.filter infixl 4 <$> (<$>) :: (Functor f r (->), Object r a, Object r b) => r a b -> f a -> f b (<$>) = fmap constrainedFmap :: (Category r, Category t, o a, o b, o (f a), o (f b)) => ( r a b -> t (f a) (f b) ) -> ConstrainedCategory r o a b -> ConstrainedCategory t o (f a) (f b) constrainedFmap q = constrained . q . unconstrained instance (Functor [] k k, o [UnitObject k]) => Functor [] (ConstrainedCategory k o) (ConstrainedCategory k o) where fmap (ConstrainedMorphism f) = ConstrainedMorphism $ fmap f instance (o (), o [()], o Void, o [Void]) => SumToProduct [] (ConstrainedCategory (->) o) (ConstrainedCategory (->) o) where sum2product = ConstrainedMorphism sum2product mapEither (ConstrainedMorphism f) = ConstrainedMorphism $ mapEither f filter (ConstrainedMorphism f) = ConstrainedMorphism $ filter f instance Functor [] Coercion Coercion where fmap Coercion = Coercion instance Functor Maybe Coercion Coercion where fmap Coercion = Coercion instance Functor (Either a) Coercion Coercion where fmap Coercion = Coercion instance Functor ((->) a) Coercion Coercion where fmap Coercion = Coercion instance Functor ((,) a) Coercion Coercion where fmap Coercion = Coercion instance Functor IO Coercion Coercion where fmap Coercion = Coercion instance Functor Complex Coercion Coercion where fmap Coercion = Coercion instance Functor [] Discrete Discrete where fmap Refl = Refl instance Functor Maybe Discrete Discrete where fmap Refl = Refl instance Functor (Either a) Discrete Discrete where fmap Refl = Refl instance Functor ((->) a) Discrete Discrete where fmap Refl = Refl instance Functor ((,) a) Discrete Discrete where fmap Refl = Refl instance Functor IO Discrete Discrete where fmap Refl = Refl instance Functor Complex Discrete Discrete where fmap Refl = Refl