{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
#if __GLASGOW_HASKELL__ >= 806
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
#endif
{-# OPTIONS_GHC -Wno-deprecations #-}
module Control.Algebra.Free
(
FreeAlgebra1 (..)
, Proof (..)
, AlgebraType0
, AlgebraType
, wrapFree
, foldFree1
, unFoldNatFree
, hoistFree1
, hoistFreeH
, joinFree1
, bindFree1
, assocFree1
, iterFree1
, cataFree1
, DayF (..)
, dayToAp
, apToDay
, Free1 (..)
, MonadList (..)
, MonadMaybe (..)
) where
import Control.Applicative ( Alternative (..)
#if __GLASGOW_HASKELL__ >= 806
, liftA2
#endif
)
import Control.Applicative.Free (Ap)
import qualified Control.Applicative.Free as Ap
import qualified Control.Applicative.Free.Fast as Fast
import qualified Control.Applicative.Free.Final as Final
import Control.Alternative.Free (Alt (..))
import qualified Control.Alternative.Free as Alt
#if __GLASGOW_HASKELL__ >= 806
import Control.Monad ( MonadPlus (..), foldM, join)
#else
import Control.Monad ( foldM, join)
#endif
import Control.Monad.Except (ExceptT (..), MonadError (..))
import Control.Monad.Free (Free)
import qualified Control.Monad.Free as Free
import qualified Control.Monad.Free.Church as Church
import Control.Monad.List (ListT (..))
import Control.Monad.Reader (MonadReader (..), ReaderT (..))
import Control.Monad.RWS.Class (MonadRWS)
import Control.Monad.RWS.Lazy as L (RWST (..))
import Control.Monad.RWS.Strict as S (RWST (..))
import Control.Monad.State.Class (MonadState (..))
import qualified Control.Monad.State.Lazy as L (StateT (..))
import qualified Control.Monad.State.Strict as S (StateT (..))
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Trans.Maybe (MaybeT (..))
import Control.Monad.Writer.Class (MonadWriter (..))
import qualified Control.Monad.Writer.Lazy as L (WriterT (..))
import qualified Control.Monad.Writer.Strict as S (WriterT (..))
#if __GLASGOW_HASKELL__ >= 806
import Control.Monad.Zip (MonadZip (..))
#endif
import Data.Kind (Constraint, Type)
import Data.Fix (Fix, cataM)
import Data.Functor.Coyoneda (Coyoneda (..), liftCoyoneda)
import Data.Functor.Day (Day (..))
import qualified Data.Functor.Day as Day
import Data.Functor.Identity (Identity (..))
import Data.Algebra.Free (AlgebraType, AlgebraType0, Proof (..))
class FreeAlgebra1 (m :: (k -> Type) -> k -> Type) where
{-# MINIMAL liftFree, foldNatFree #-}
liftFree :: AlgebraType0 m f => f a -> m f a
foldNatFree
:: forall d f a .
( AlgebraType m d
, AlgebraType0 m f
)
=> (forall x. f x -> d x)
-> (m f a -> d a)
codom1 :: forall f. AlgebraType0 m f => Proof (AlgebraType m (m f)) (m f)
default codom1 :: forall a. AlgebraType m (m a)
=> Proof (AlgebraType m (m a)) (m a)
codom1 = Proof
forget1 :: forall f. AlgebraType m f => Proof (AlgebraType0 m f) (m f)
default forget1 :: forall a. AlgebraType0 m a
=> Proof (AlgebraType0 m a) (m a)
forget1 = Proof
wrapFree
:: forall (m :: (Type -> Type) -> Type -> Type)
(f :: Type -> Type)
a .
( FreeAlgebra1 m
, AlgebraType0 m f
, Monad (m f)
)
=> f (m f a)
-> m f a
wrapFree = join . liftFree
{-# INLINABLE wrapFree #-}
foldFree1 :: forall m f a .
( FreeAlgebra1 m
, AlgebraType m f
)
=> m f a
-> f a
foldFree1 = case forget1 :: Proof (AlgebraType0 m f) (m f) of
Proof -> foldNatFree id
{-# INLINABLE foldFree1 #-}
unFoldNatFree
:: ( FreeAlgebra1 m
, AlgebraType0 m f
)
=> (forall x . m f x -> d x)
-> f a -> d a
unFoldNatFree nat = nat . liftFree
hoistFree1 :: forall m f g a .
( FreeAlgebra1 m
, AlgebraType0 m g
, AlgebraType0 m f
)
=> (forall x. f x -> g x)
-> m f a
-> m g a
hoistFree1 nat = case codom1 :: Proof (AlgebraType m (m g)) (m g) of
Proof -> foldNatFree (liftFree . nat)
{-# INLINABLE [1] hoistFree1 #-}
{-# RULES
"hositFree1/foldNatFree"
forall (nat :: forall (x :: k). g x -> c x)
(nat0 :: forall (x :: k). f x -> g x)
(f :: m f a).
foldNatFree nat (hoistFree1 nat0 f) = foldNatFree (nat . nat0) f
#-}
hoistFreeH :: forall m n f a .
( FreeAlgebra1 m
, FreeAlgebra1 n
, AlgebraType0 m f
, AlgebraType0 n f
, AlgebraType m (n f)
)
=> m f a
-> n f a
hoistFreeH = foldNatFree liftFree
{-# INLINABLE [1] hoistFreeH #-}
{-# RULES
"hoistFreeH/foldNatFree" forall (nat :: forall (x :: k). f x -> c x)
(f :: AlgebraType m c => m f a).
foldNatFree nat (hoistFreeH f) = foldNatFree nat f
#-}
joinFree1 :: forall m f a .
( FreeAlgebra1 m
, AlgebraType0 m f
)
=> m (m f) a
-> m f a
joinFree1 = case codom1 :: Proof (AlgebraType m (m f)) (m f) of
Proof -> case forget1 :: Proof (AlgebraType0 m (m f)) (m (m f)) of
Proof -> foldFree1
{-# INLINABLE joinFree1 #-}
bindFree1 :: forall m f g a .
( FreeAlgebra1 m
, AlgebraType0 m g
, AlgebraType0 m f
)
=> m f a
-> (forall x . f x -> m g x)
-> m g a
bindFree1 mfa nat = case codom1 :: Proof (AlgebraType m (m g)) (m g) of
Proof -> foldNatFree nat mfa
{-# INLINABLE bindFree1 #-}
assocFree1 :: forall m f a .
( FreeAlgebra1 m
, AlgebraType m f
, Functor (m (m f))
)
=> m f (m f a)
-> m (m f) (f a)
assocFree1 = case forget1 :: Proof (AlgebraType0 m f) (m f) of
Proof -> case codom1 :: Proof (AlgebraType m (m f)) (m f) of
Proof -> case forget1 :: Proof (AlgebraType0 m (m f)) (m (m f)) of
Proof -> case codom1 :: Proof (AlgebraType m (m (m f))) (m (m f)) of
Proof -> fmap foldFree1 . foldNatFree (hoistFree1 liftFree . liftFree)
{-# INLINABLE assocFree1 #-}
cataFree1 :: forall m f a .
( FreeAlgebra1 m
, AlgebraType m f
, Monad f
, Traversable (m f)
)
=> Fix (m f)
-> f a
cataFree1 = cataM foldFree1
iterFree1 :: forall m f a .
( FreeAlgebra1 m
, AlgebraType0 m f
, AlgebraType m Identity
)
=> (forall x . f x -> x)
-> m f a
-> a
iterFree1 f = runIdentity . foldNatFree (Identity . f)
{-# INLINABLE iterFree1 #-}
type instance AlgebraType0 Coyoneda g = ()
type instance AlgebraType Coyoneda g = Functor g
instance FreeAlgebra1 Coyoneda where
liftFree = liftCoyoneda
foldNatFree nat (Coyoneda ba fx) = ba <$> nat fx
type instance AlgebraType0 Ap g = Functor g
type instance AlgebraType Ap g = Applicative g
instance FreeAlgebra1 Ap where
liftFree = Ap.liftAp
foldNatFree = Ap.runAp
type instance AlgebraType0 Fast.Ap g = Functor g
type instance AlgebraType Fast.Ap g = Applicative g
instance FreeAlgebra1 Fast.Ap where
liftFree = Fast.liftAp
foldNatFree = Fast.runAp
type instance AlgebraType0 Final.Ap g = Functor g
type instance AlgebraType Final.Ap g = Applicative g
instance FreeAlgebra1 Final.Ap where
liftFree = Final.liftAp
foldNatFree = Final.runAp
newtype DayF f a = DayF { runDayF :: Day f f a}
deriving (Functor, Applicative)
dayToAp :: Applicative f => Day f f a -> Ap f a
dayToAp = hoistFreeH . DayF
apToDay :: Applicative f => Ap f a -> Day f f a
apToDay = runDayF . hoistFreeH
type instance AlgebraType0 DayF g = Applicative g
type instance AlgebraType DayF g = Applicative g
instance FreeAlgebra1 DayF where
liftFree fa = DayF $ Day fa fa const
foldNatFree nat (DayF day)
= Day.dap . Day.trans2 nat . Day.trans1 nat $ day
type instance AlgebraType0 Free f = Functor f
type instance AlgebraType Free m = Monad m
instance FreeAlgebra1 Free where
liftFree = Free.liftF
foldNatFree = Free.foldFree
type instance AlgebraType0 Church.F f = Functor f
type instance AlgebraType Church.F m = Monad m
instance FreeAlgebra1 Church.F where
liftFree = Church.liftF
foldNatFree = Church.foldF
type instance AlgebraType0 Alt f = Functor f
type instance AlgebraType Alt m = Alternative m
instance FreeAlgebra1 Alt where
liftFree = Alt.liftAlt
foldNatFree = Alt.runAlt
type instance AlgebraType0 (L.StateT s) m = Monad m
type instance AlgebraType (L.StateT s) m = ( MonadState s m )
instance FreeAlgebra1 (L.StateT s) where
liftFree = lift
foldNatFree nat ma = do
(a, s) <- get >>= nat . L.runStateT ma
put s
return a
type instance AlgebraType0 (S.StateT s) m = Monad m
type instance AlgebraType (S.StateT s) m = ( MonadState s m )
instance FreeAlgebra1 (S.StateT s) where
liftFree :: Monad m => m a -> S.StateT s m a
liftFree = lift
foldNatFree nat ma = do
(a, s) <- get >>= nat . S.runStateT ma
put s
return a
type instance AlgebraType0 (L.WriterT w) m = ( Monad m, Monoid w )
type instance AlgebraType (L.WriterT w) m = ( MonadWriter w m )
instance FreeAlgebra1 (L.WriterT w) where
liftFree = lift
foldNatFree nat (L.WriterT m) = fst <$> nat m
type instance AlgebraType0 (S.WriterT w) m = ( Monad m, Monoid w )
type instance AlgebraType (S.WriterT w) m = ( MonadWriter w m )
instance FreeAlgebra1 (S.WriterT w) where
liftFree = lift
foldNatFree nat (S.WriterT m) = fst <$> nat m
type instance AlgebraType0 (ReaderT r) m = ( Monad m )
type instance AlgebraType (ReaderT r) m = ( MonadReader r m )
instance FreeAlgebra1 (ReaderT r :: (Type -> Type) -> Type -> Type) where
liftFree = lift
foldNatFree nat (ReaderT g) =
ask >>= nat . g
type instance AlgebraType0 (ExceptT e) m = ( Monad m )
type instance AlgebraType (ExceptT e) m = ( MonadError e m )
instance FreeAlgebra1 (ExceptT e) where
liftFree = lift
foldNatFree nat (ExceptT m) = do
ea <- nat m
case ea of
Left e -> throwError e
Right a -> return a
type instance AlgebraType0 (L.RWST r w s) m = ( Monad m, Monoid w )
type instance AlgebraType (L.RWST r w s) m = MonadRWS r w s m
instance FreeAlgebra1 (L.RWST r w s) where
liftFree = lift
foldNatFree nat (L.RWST fn) = do
r <- ask
s <- get
(a, s', w) <- nat $ fn r s
put s'
tell w
return a
type instance AlgebraType0 (S.RWST r w s) m = ( Monad m, Monoid w )
type instance AlgebraType (S.RWST r w s) m = MonadRWS r w s m
instance FreeAlgebra1 (S.RWST r w s) where
liftFree = lift
foldNatFree nat (S.RWST fn) = do
r <- ask
s <- get
(a, s', w) <- nat $ fn r s
put s'
tell w
return a
class Monad m => MonadList m where
mempty1 :: m a
mappend1 :: m a -> m a -> m a
mappend1_ :: MonadList m => a -> a -> m a
mappend1_ a b = return a `mappend1` return b
{-# INLINABLE mappend1_ #-}
instance Monad m => MonadList (ListT m) where
mempty1 = ListT (return [])
mappend1 (ListT ma) (ListT mb) = ListT $ mappend <$> ma <*> mb
type instance AlgebraType0 ListT f = ( Monad f )
type instance AlgebraType ListT m = ( MonadList m )
instance FreeAlgebra1 ListT where
liftFree = lift
foldNatFree nat (ListT mas) = do
as <- nat mas
empty1 <- mempty1
foldM (\x y -> x `mappend1_` y) empty1 as
newtype Free1 (c :: (Type -> Type) -> Constraint)
(f :: Type -> Type)
a
= Free1 {
runFree1 :: forall g. c g => (forall x. f x -> g x) -> g a
}
#if __GLASGOW_HASKELL__ >= 806
instance (forall h. c h => Functor h)
=> Functor (Free1 c f) where
fmap :: forall a b. (a -> b) -> Free1 c f a -> Free1 c f b
fmap f (Free1 g) = Free1 $ \h -> fmap f (g h)
a <$ Free1 g = Free1 $ \h -> a <$ g h
instance (forall h. c h => Applicative h)
=> Applicative (Free1 c f) where
pure a = Free1 $ \_ -> pure a
Free1 f <*> Free1 g = Free1 $ \h -> f h <*> g h
liftA2 f (Free1 x) (Free1 y) = Free1 $ \h -> liftA2 f (x h) (y h)
Free1 f *> Free1 g = Free1 $ \h -> f h *> g h
Free1 f <* Free1 g = Free1 $ \h -> f h <* g h
instance (forall h. c h => Monad h)
=> Monad (Free1 c f) where
return = pure
Free1 f >>= k = Free1 $ \h ->
f h >>= (\a -> case k a of Free1 l -> l h)
Free1 f >> Free1 g = Free1 $ \h -> f h >> g h
#if __GLASGOW_HASKELL__ < 808
fail s = Free1 $ \_ -> fail s
#endif
instance (forall h. c h => Alternative h)
=> Alternative (Free1 c f) where
empty = Free1 $ \_ -> empty
Free1 f <|> Free1 g = Free1 $ \h -> f h <|> g h
some (Free1 f) = Free1 $ \h -> some (f h)
many (Free1 f) = Free1 $ \h -> many (f h)
instance (forall h. c h => MonadPlus h)
=> MonadPlus (Free1 c f) where
mzero = Free1 $ \_ -> mzero
Free1 f `mplus` Free1 g = Free1 $ \h -> f h `mplus` g h
instance (forall h. c h => MonadZip h)
=> MonadZip (Free1 c f) where
Free1 f `mzip` Free1 g = Free1 $ \h -> f h `mzip` g h
mzipWith k (Free1 f) (Free1 g) = Free1 $ \h -> mzipWith k (f h) (g h)
munzip (Free1 f) = (Free1 $ \h -> fst (munzip (f h)), Free1 $ \h -> snd (munzip (f h)))
type instance AlgebraType0 (Free1 c) f = ()
type instance AlgebraType (Free1 c) f = (c f)
instance (forall f. c (Free1 c f)) => FreeAlgebra1 (Free1 c) where
liftFree = \fa -> Free1 $ \g -> g fa
foldNatFree nat (Free1 f) = f nat
#endif
class MonadMaybe m where
point :: forall a. m a
instance Monad m => MonadMaybe (MaybeT m) where
point = MaybeT (return Nothing)
type instance AlgebraType0 MaybeT m = ( Monad m )
type instance AlgebraType MaybeT m = ( Monad m, MonadMaybe m )
instance FreeAlgebra1 MaybeT where
liftFree = lift
foldNatFree nat (MaybeT mma) =
nat mma >>= \ma -> case ma of
Nothing -> point
Just a -> return a