fir-0.1.0.0: src/Control/Monad/Indexed.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-|
Module: Control.Monad.Indexed
Indexed functors and monads.
This module includes two versions, as described in Conor McBride's paper
/Kleisli Arrows of Outrageous Fortune/.
McBride-style indexed monads are usually written with an @ix@ /suffix/,
whereas AtKey-style indexed monads are usually written with an @ix@ /prefix/.
-}
module Control.Monad.Indexed
( -- * McBride-style indexed monads
FunctorIx(fmapIx), MonadIx(returnIx, extendIx), MonadIxFail(fail)
-- ** Identity indexed monad
, Id(Id, runId)
-- ** Codensity transformation
, Codensity(Codensity, runCodensity)
-- * Atkey-style indexed monads
-- ** Representing Atkey indexed monads using the /At Key/ trick
, (:=)(AtKey), atKey, withKey
-- ** Atkey functor operations
, ixFmap, (<<$>>), (<<$), ($>>), (<<&>>)
-- ** Atkey applicative operations
, IxApplicative((<<*>>))
, (*>>), (<<*), ixLiftA2, ixLiftA3, ixLiftA4
-- ** Foldable/traversable operations
, IxF(..)
, ixTraverse, ixFor
, ixTraverse_, ixFor_
-- * Rebindable syntax for @do@ notation
, (>>=), (=<<), (>>), (<<), return, pure, ixPure,
)
where
-- base
import Data.Coerce
( coerce )
import Data.Foldable
( traverse_ )
import Data.Kind
( Type )
import Prelude
hiding ( Functor(..), Applicative(..), Monad(..), (=<<) )
import qualified Prelude
------------------------------------------------
-- indexed monads (à la McBride)
class FunctorIx ( f :: (k -> Type) -> (k -> Type) ) where
fmapIx :: ( forall ix. p ix -> q ix )
-> ( forall ix. f p ix -> f q ix )
class FunctorIx m => MonadIx m where
returnIx :: p ix -> m p ix
-- | Demonic bind.
extendIx :: ( forall ix. p ix -> m q ix )
-> ( forall ix. m p ix -> m q ix )
class MonadIx m => MonadIxFail m where
fail :: String -> m (a := j) i
------------------------------------------------------------
-- identity indexed monad
newtype Id p i = Id { runId :: p i }
instance FunctorIx Id where
fmapIx f (Id a) = Id (f a)
instance MonadIx Id where
extendIx f (Id a) = f a
returnIx = Id
------------------------------------------------------------
-- codensity transformation
-- | Demonic codensity transformation.
--
-- For any @(f :: Type -> Type)@,
-- @Codensity f@ is guaranteed to be an indexed monad.
--
-- This is especially useful for manipulating ASTs.
newtype Codensity (f :: t -> Type) (p :: ix -> Type) (i :: ix) where
Codensity
:: { runCodensity
:: forall (q :: ix -> t)
. ( ( forall (j :: ix). p j -> f (q j) ) -> f (q i) )
}
-> Codensity f p i
instance FunctorIx (Codensity f) where
fmapIx :: ( forall ix. p ix -> q ix )
-> ( forall ix. Codensity f p ix -> Codensity f q ix )
fmapIx f (Codensity m) = Codensity ( \k -> m ( k . f ) )
instance MonadIx (Codensity f) where
returnIx :: p i -> Codensity f p i
returnIx a = Codensity ( \k -> k a )
extendIx :: ( forall ix. p ix -> Codensity f q ix )
-> ( forall ix. Codensity f p ix -> Codensity f q ix )
extendIx f (Codensity ma) = Codensity ( \k -> ma ( \a -> runCodensity (f a) k ) )
------------------------------------------------
-- Atkey indexing
-- | The /At Key/ datatype allows us to express Atkey-style indexed monads
-- in terms of McBride-style indexed monads.
data (:=) :: Type -> i -> (i -> Type) where
AtKey :: a -> (a := i) i
atKey :: (a := j) i -> a
atKey (AtKey a) = a
instance Show a => Show ( (a := i) j ) where
show (AtKey a) = "AtKey " ++ show a
withKey :: (a -> b) -> (a := i) j -> (b := i) j
withKey f (AtKey a) = AtKey (f a)
------------------------------------------------------------
-- useful operators & functions for AtKey-style indexing
ixFmap :: forall m i j a b. FunctorIx m => (a -> b) -> m (a := j) i -> m (b := j) i
ixFmap f = fmapIx ( withKey f )
infixl 4 <<$>>
infixl 4 <<$
infixl 4 $>>
infixl 1 <<&>>
(<<$>>) :: FunctorIx f => (a -> b) -> f (a := j) i -> f (b := j) i
(<<$>>) = ixFmap
(<<$) :: FunctorIx f => a -> f (b := j) i -> f (a := j) i
(<<$) = ixFmap . const
($>>) :: FunctorIx f => f (a := j) i -> b -> f (b := j) i
($>>) = flip (<<$)
(<<&>>) :: FunctorIx f => f (a := j) i -> (a -> b) -> f (b := j) i
(<<&>>) = flip ixFmap
infixl 4 <<*>>
class FunctorIx f => IxApplicative f where
(<<*>>) :: f ((a -> b) := j) i -> (f (a := k) j -> f (b := k) i)
ixPure :: a -> f (a := i) i
instance (FunctorIx m, MonadIx m) => IxApplicative m where
mf <<*>> ma = mf >>= (<<$>> ma)
ixPure = returnIx . AtKey
infixl 4 *>>
infixl 4 <<*
(*>>) :: IxApplicative f => f (a := j) i -> f (b := k) j -> f (b := k) i
fa *>> fb = (id <<$ fa) <<*>> fb
(<<*) :: IxApplicative f => f (a := j) i -> f (b := k) j -> f (a := k) i
fa <<* fb = (const <<$>> fa) <<*>> fb
ixLiftA2 :: IxApplicative f
=> (a -> b -> c)
-> f (a := j) i -> f (b := k) j -> f (c := k) i
ixLiftA2 f a b = f <<$>> a <<*>> b
ixLiftA3 :: IxApplicative f
=> (a -> b -> c -> d)
-> f (a := j) i -> f (b := k) j -> f (c := l) k -> f (d := l) i
ixLiftA3 f a b c = f <<$>> a <<*>> b <<*>> c
ixLiftA4 :: IxApplicative f
=> (a -> b -> c -> d -> e)
-> f (a := j) i -> f (b := k) j -> f (c := l) k -> f (d := m) l -> f (e := m) i
ixLiftA4 f a b c d = f <<$>> a <<*>> b <<*>> c <<*>> d
------------------------------------------------
-- foldable/traversable
-- newtype to put type variable last
newtype IxF f i j a = IxF { ixF :: f (a := j) i }
instance FunctorIx f => Prelude.Functor (IxF f i j) where
fmap :: forall a b. (a -> b) -> (IxF f i j a -> IxF f i j b)
fmap = coerce ( ixFmap @f @i @j @a @b)
instance IxApplicative f => Prelude.Applicative (IxF f i i) where
pure :: forall a. a -> IxF f i i a
pure = coerce ( ixPure @f @a @i )
(<*>) :: forall a b. IxF f i i (a -> b) -> (IxF f i i a -> IxF f i i b)
(<*>) = coerce ( (<<*>>) @f @a @b @i @i @i )
ixTraverse
:: forall f t a b i.
(Prelude.Traversable t, IxApplicative f)
=> (a -> f (b := i) i) -> t a -> f (t b := i) i
ixTraverse f = coerce ( traverse @t (IxF . f) )
ixFor
:: forall f t a b i.
(Prelude.Traversable t, IxApplicative f)
=> t a -> (a -> f (b := i) i) -> f (t b := i) i
ixFor = flip ixTraverse
ixTraverse_
:: forall f t a b i.
(Prelude.Foldable t, IxApplicative f)
=> (a -> f (b := i) i) -> t a -> f (() := i) i
ixTraverse_ f = coerce ( traverse_ @t (IxF . f) )
ixFor_
:: (Prelude.Foldable t, IxApplicative f)
=> t a -> (a -> f (b := i) i) -> f (() := i) i
ixFor_ = flip ixTraverse_
------------------------------------------------
-- rebindable syntax
infixl 1 >>=
-- | Angelic bind.
(>>=) :: MonadIx m => m (a := j) i -> (a -> m q j) -> m q i
c >>= f = extendIx ( \ (AtKey a) -> f a ) c
infixl 1 >>
(>>) :: MonadIx m => m (a := j) i -> m q j -> m q i
ma >> mb = ma >>= const mb
infixr 1 <<
(<<) :: MonadIx m => m q j -> m (a := j) i -> m q i
(<<) = flip (>>)
infixr 1 =<<
(=<<) :: MonadIx m => (a -> m q j) -> m (a := j) i -> m q i
(=<<) = flip (>>=)
return, pure :: MonadIx m => a -> m (a := i) i
return = returnIx . AtKey
pure = returnIx . AtKey