indexed-transformers 0.1.0.4 → 0.2.0.0
raw patch · 15 files changed
+960/−224 lines, 15 filesdep +QuickCheckdep +doctest-paralleldep +hspecdep ~basedep ~freedep ~mtlPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, doctest-parallel, hspec, indexed-transformers, kan-extensions
Dependency ranges changed: base, free, mtl, transformers
API changes (from Hackage documentation)
- Control.Monad.Trans.Indexed.Free: [IxMap] :: (x -> y) -> f i j x -> IxMap f i j y
- Control.Monad.Trans.Indexed.Free: data IxMap f i j x
- Control.Monad.Trans.Indexed.Free: instance forall k1 k2 (f :: k1 -> k2 -> * -> *) (i :: k1) (j :: k2). GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.IxMap f i j)
- Control.Monad.Trans.Indexed.Free: type IxFunctor f = forall i j. Functor (f i j)
- Control.Monad.Trans.Indexed.Free.Fold: FreeIx :: (forall t. (IxMonadTrans t, Monad m) => (forall i j x. g i j x -> t i j m x) -> t i j m x) -> FreeIx g i j m x
- Control.Monad.Trans.Indexed.Free.Fold: [runFreeIx] :: FreeIx g i j m x -> forall t. (IxMonadTrans t, Monad m) => (forall i j x. g i j x -> t i j m x) -> t i j m x
- Control.Monad.Trans.Indexed.Free.Fold: instance Control.Monad.Trans.Indexed.Free.IxMonadTransFree Control.Monad.Trans.Indexed.Free.Fold.FreeIx
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f i j)
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, GHC.Base.Monad m, i GHC.Types.~ j) => Control.Monad.Free.Class.MonadFree (f i j) (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Fold: instance forall k (f :: k -> k -> * -> *). Control.Monad.Trans.Indexed.Free.IxFunctor f => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Free.Fold.FreeIx f)
- Control.Monad.Trans.Indexed.Free.Fold: newtype FreeIx g i j m x
- Control.Monad.Trans.Indexed.Free.Wrap: FreeIx :: m (WrapIx f i j m x) -> FreeIx f i j m x
- Control.Monad.Trans.Indexed.Free.Wrap: [Unwrap] :: x -> WrapIx f i i m x
- Control.Monad.Trans.Indexed.Free.Wrap: [Wrap] :: f i j (FreeIx f j k m x) -> WrapIx f i k m x
- Control.Monad.Trans.Indexed.Free.Wrap: [runFreeIx] :: FreeIx f i j m x -> m (WrapIx f i j m x)
- Control.Monad.Trans.Indexed.Free.Wrap: data WrapIx f i j m x
- Control.Monad.Trans.Indexed.Free.Wrap: instance Control.Monad.Trans.Indexed.Free.IxMonadTransFree Control.Monad.Trans.Indexed.Free.Wrap.FreeIx
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f i j)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.Wrap.WrapIx f i j m)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.Free.IxFunctor f, GHC.Base.Monad m, i GHC.Types.~ j) => Control.Monad.Free.Class.MonadFree (f i j) (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f i j m)
- Control.Monad.Trans.Indexed.Free.Wrap: instance forall k (f :: k -> k -> * -> *). Control.Monad.Trans.Indexed.Free.IxFunctor f => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Free.Wrap.FreeIx f)
- Control.Monad.Trans.Indexed.Free.Wrap: newtype FreeIx f i j m x
+ Control.Monad.Trans.Indexed.Codensity: CodensityIx :: (forall b k. (a -> t j k m b) -> t i k m b) -> CodensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: PredensityIx :: (forall b. (a -> t j m b) -> t i m b) -> PredensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: [runCodensityIx] :: CodensityIx t i j m a -> forall b k. (a -> t j k m b) -> t i k m b
+ Control.Monad.Trans.Indexed.Codensity: [runPredensityIx] :: PredensityIx t i j m a -> forall b. (a -> t j m b) -> t i m b
+ Control.Monad.Trans.Indexed.Codensity: instance (i GHC.Types.~ j, GHC.Base.Monad m) => Control.Monad.State.Class.MonadState i (Control.Monad.Trans.Indexed.Codensity.PredensityIx Control.Monad.Trans.Reader.ReaderT i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance Control.Monad.Trans.Indexed.State.IxMonadTransState (Control.Monad.Trans.Indexed.Codensity.PredensityIx Control.Monad.Trans.Reader.ReaderT)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (i :: k) (j :: k) (t :: k -> k -> (* -> *) -> * -> *) (m :: * -> *). (i GHC.Types.~ j, GHC.Base.Alternative (t i j m), Control.Monad.Trans.Indexed.IxMonadTrans t, GHC.Base.Monad m) => GHC.Base.Alternative (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (i :: k) (j :: k) (t :: k -> k -> (* -> *) -> * -> *) (m :: * -> *). (i GHC.Types.~ j, GHC.Base.Alternative (t i j m), Control.Monad.Trans.Indexed.IxMonadTrans t, GHC.Base.Monad m) => GHC.Base.MonadPlus (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (t :: k -> (* -> *) -> * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Class.MonadTrans (t i), i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Codensity.PredensityIx t i j)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (t :: k -> (* -> *) -> * -> *). (forall (i :: k). Control.Monad.Trans.Class.MonadTrans (t i)) => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Codensity.PredensityIx t)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (t :: k -> k -> (* -> *) -> * -> *) (i :: k) (j :: k). (Control.Monad.Trans.Indexed.IxMonadTrans t, i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k (t :: k -> k -> (* -> *) -> * -> *). Control.Monad.Trans.Indexed.IxMonadTrans t => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Codensity.CodensityIx t)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 (i :: k1) (j :: k1) (t :: k1 -> k2 -> k3 -> *) (m :: k2). (i GHC.Types.~ j) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Codensity.PredensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 (i :: k1) (j :: k1) (t :: k1 -> k2 -> k3 -> *) (m :: k2). (i GHC.Types.~ j) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Codensity.PredensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 (t :: k2 -> k3 -> k1 -> *) (i :: k2) (j :: k2) (m :: k3). GHC.Base.Functor (Control.Monad.Trans.Indexed.Codensity.PredensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 k4 (i :: k1) (j :: k1) (t :: k1 -> k2 -> k3 -> k4 -> *) (m :: k3). (i GHC.Types.~ j) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 k4 (i :: k1) (j :: k1) (t :: k1 -> k2 -> k3 -> k4 -> *) (m :: k3). (i GHC.Types.~ j) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: instance forall k1 k2 k3 k4 (t :: k3 -> k1 -> k4 -> k2 -> *) (i :: k3) (j :: k3) (m :: k4). GHC.Base.Functor (Control.Monad.Trans.Indexed.Codensity.CodensityIx t i j m)
+ Control.Monad.Trans.Indexed.Codensity: liftCodensityIx :: (IxMonadTrans t, Monad m) => t i j m a -> CodensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: liftFromStateIx :: Monad m => StateIx i j m a -> PredensityIx ReaderT i j m a
+ Control.Monad.Trans.Indexed.Codensity: lowerCodensityIx :: (IxMonadTrans t, Monad m) => CodensityIx t i j m a -> t i j m a
+ Control.Monad.Trans.Indexed.Codensity: lowerToStateIx :: Monad m => PredensityIx ReaderT i j m a -> StateIx i j m a
+ Control.Monad.Trans.Indexed.Codensity: newtype CodensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: newtype PredensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: resetCodensityIx :: (IxMonadTrans t, Monad m) => CodensityIx t i j m a -> CodensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: shiftCodensityIx :: (IxMonadTrans t, Monad m) => (forall b k. (a -> t j k m b) -> CodensityIx t i k m b) -> CodensityIx t i j m a
+ Control.Monad.Trans.Indexed.Codensity: toCodensity :: CodensityIx t i i m a -> Codensity (t i i m) a
+ Control.Monad.Trans.Indexed.Codensity: wrapCodensityIx :: (forall a k. t j k (m :: Type -> Type) a -> t i k m a) -> CodensityIx t i j m ()
+ Control.Monad.Trans.Indexed.Free: FoldFreeIx :: (forall t. (IxMonadTrans t, Monad m) => (forall k l a. g k l a -> t k l m a) -> t i j m x) -> FoldFreeIx g i j m x
+ Control.Monad.Trans.Indexed.Free: FreeIx :: m (WrapFreeIx f i j m x) -> FreeIx f i j m x
+ Control.Monad.Trans.Indexed.Free: ImproveFreeIx :: CodensityIx (FreeIx f) i j m a -> ImproveFreeIx f i j m a
+ Control.Monad.Trans.Indexed.Free: [CoyonedaIx] :: (x -> y) -> f i j x -> CoyonedaIx f i j y
+ Control.Monad.Trans.Indexed.Free: [Unwrap] :: x -> WrapFreeIx f i i m x
+ Control.Monad.Trans.Indexed.Free: [Wrap] :: f i j (FreeIx f j k m x) -> WrapFreeIx f i k m x
+ Control.Monad.Trans.Indexed.Free: [runFoldFreeIx] :: FoldFreeIx g i j m x -> forall t. (IxMonadTrans t, Monad m) => (forall k l a. g k l a -> t k l m a) -> t i j m x
+ Control.Monad.Trans.Indexed.Free: [runFreeIx] :: FreeIx f i j m x -> m (WrapFreeIx f i j m x)
+ Control.Monad.Trans.Indexed.Free: [runImproveFreeIx] :: ImproveFreeIx f i j m a -> CodensityIx (FreeIx f) i j m a
+ Control.Monad.Trans.Indexed.Free: data CoyonedaIx f i j x
+ Control.Monad.Trans.Indexed.Free: data WrapFreeIx f i j m x
+ Control.Monad.Trans.Indexed.Free: improveIx :: (forall k l. Functor (f k l), Monad m) => (forall freeIx. IxMonadTransFree freeIx => freeIx f i j m a) -> FreeIx f i j m a
+ Control.Monad.Trans.Indexed.Free: instance Control.Monad.Trans.Indexed.Free.IxMonadTransFree Control.Monad.Trans.Indexed.Free.FoldFreeIx
+ Control.Monad.Trans.Indexed.Free: instance Control.Monad.Trans.Indexed.Free.IxMonadTransFree Control.Monad.Trans.Indexed.Free.FreeIx
+ Control.Monad.Trans.Indexed.Free: instance Control.Monad.Trans.Indexed.Free.IxMonadTransFree Control.Monad.Trans.Indexed.Free.ImproveFreeIx
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Free.FoldFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Free.FreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Free.FoldFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k) (m :: * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j, GHC.Base.Monad m) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Free.FreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Free.FoldFreeIx f i j)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Free.FreeIx f i j)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.FoldFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.FreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), GHC.Base.Monad m) => GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.WrapFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), GHC.Base.Monad m, i GHC.Types.~ j) => Control.Monad.Free.Class.MonadFree (f i j) (Control.Monad.Trans.Indexed.Free.FoldFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *) (m :: * -> *) (i :: k) (j :: k). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l), GHC.Base.Monad m, i GHC.Types.~ j) => Control.Monad.Free.Class.MonadFree (f i j) (Control.Monad.Trans.Indexed.Free.FreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l)) => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Free.FoldFreeIx f)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l)) => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Free.FreeIx f)
+ Control.Monad.Trans.Indexed.Free: instance forall k (f :: k -> k -> * -> *). (forall (k1 :: k) (l :: k). GHC.Base.Functor (f k1 l)) => Control.Monad.Trans.Indexed.IxMonadTrans (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 (f :: k1 -> k1 -> * -> *) (i :: k1) (j :: k1) (m :: * -> *). GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 (f :: k1 -> k1 -> * -> *) (i :: k1) (j :: k1). (forall (k :: k1) (l :: k1). GHC.Base.Functor (f k l), i GHC.Types.~ j) => Control.Monad.Trans.Class.MonadTrans (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f i j)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 (f :: k1 -> k1 -> * -> *) (m :: * -> *) (i :: k1) (j :: k1). (forall (k :: k1) (l :: k1). GHC.Base.Functor (f k l), GHC.Base.Monad m, i GHC.Types.~ j) => Control.Monad.Free.Class.MonadFree (f i j) (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 (i :: k1) (j :: k1) (f :: k1 -> k1 -> * -> *) (m :: * -> *). (i GHC.Types.~ j) => GHC.Base.Applicative (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 (i :: k1) (j :: k1) (f :: k1 -> k1 -> * -> *) (m :: * -> *). (i GHC.Types.~ j) => GHC.Base.Monad (Control.Monad.Trans.Indexed.Free.ImproveFreeIx f i j m)
+ Control.Monad.Trans.Indexed.Free: instance forall k1 k2 (f :: k1 -> k2 -> * -> *) (i :: k1) (j :: k2). GHC.Base.Functor (Control.Monad.Trans.Indexed.Free.CoyonedaIx f i j)
+ Control.Monad.Trans.Indexed.Free: newtype FoldFreeIx g i j m x
+ Control.Monad.Trans.Indexed.Free: newtype FreeIx f i j m x
+ Control.Monad.Trans.Indexed.Free: newtype ImproveFreeIx f i j m a
+ Control.Monad.Trans.Indexed.Free: type FreerIx freeIx f = freeIx (CoyonedaIx f)
+ Control.Monad.Trans.Indexed.State: class (IxMonadTrans t, forall i m. Monad m => MonadState i (t i i m)) => IxMonadTransState t
+ Control.Monad.Trans.Indexed.State: getIx :: (IxMonadTransState t, Monad m) => t i i m i
+ Control.Monad.Trans.Indexed.State: instance Control.Monad.Trans.Indexed.State.IxMonadTransState Control.Monad.Trans.Indexed.State.StateIx
+ Control.Monad.Trans.Indexed.State: stateIx :: (IxMonadTransState t, Monad m) => (i -> m (x, j)) -> t i j m x
- Control.Monad.Trans.Indexed.Free: class (forall f. IxFunctor f => IxMonadTrans (freeIx f), forall f m i j. (IxFunctor f, Monad m, i ~ j) => MonadFree (f i j) (freeIx f i j m)) => IxMonadTransFree freeIx
+ Control.Monad.Trans.Indexed.Free: class (forall f. (forall k l. Functor (f k l)) => IxMonadTrans (freeIx f), forall f m i j. (forall k l. Functor (f k l), Monad m, i ~ j) => MonadFree (f i j) (freeIx f i j m)) => IxMonadTransFree freeIx
- Control.Monad.Trans.Indexed.Free: coerceFreeIx :: (IxMonadTransFree freeIx0, IxMonadTransFree freeIx1, IxFunctor f, Monad m) => freeIx0 f i j m x -> freeIx1 f i j m x
+ Control.Monad.Trans.Indexed.Free: coerceFreeIx :: (IxMonadTransFree freeIx0, IxMonadTransFree freeIx1, forall k l. Functor (f k l), Monad m) => freeIx0 f i j m x -> freeIx1 f i j m x
- Control.Monad.Trans.Indexed.Free: foldFreeIx :: (IxMonadTransFree freeIx, IxFunctor f, IxMonadTrans t, Monad m) => (forall i j x. f i j x -> t i j m x) -> freeIx f i j m x -> t i j m x
+ Control.Monad.Trans.Indexed.Free: foldFreeIx :: (IxMonadTransFree freeIx, forall k l. Functor (f k l), IxMonadTrans t, Monad m) => (forall k l a. f k l a -> t k l m a) -> freeIx f i j m x -> t i j m x
- Control.Monad.Trans.Indexed.Free: foldFreerIx :: (IxMonadTransFree freeIx, IxMonadTrans t, Monad m) => (forall i j x. f i j x -> t i j m x) -> freeIx (IxMap f) i j m x -> t i j m x
+ Control.Monad.Trans.Indexed.Free: foldFreerIx :: (IxMonadTransFree freeIx, IxMonadTrans t, Monad m) => (forall k l a. f k l a -> t k l m a) -> FreerIx freeIx f i j m x -> t i j m x
- Control.Monad.Trans.Indexed.Free: hoistFreeIx :: (IxMonadTransFree freeIx, IxFunctor f, IxFunctor g, Monad m) => (forall i j x. f i j x -> g i j x) -> freeIx f i j m x -> freeIx g i j m x
+ Control.Monad.Trans.Indexed.Free: hoistFreeIx :: (IxMonadTransFree freeIx, forall k l. Functor (f k l), forall k l. Functor (g k l), Monad m) => (forall k l a. f k l a -> g k l a) -> freeIx f i j m x -> freeIx g i j m x
- Control.Monad.Trans.Indexed.Free: hoistFreerIx :: (IxMonadTransFree freeIx, Monad m) => (forall i j x. f i j x -> g i j x) -> freeIx (IxMap f) i j m x -> freeIx (IxMap g) i j m x
+ Control.Monad.Trans.Indexed.Free: hoistFreerIx :: (IxMonadTransFree freeIx, Monad m) => (forall k l a. f k l a -> g k l a) -> FreerIx freeIx f i j m x -> FreerIx freeIx g i j m x
- Control.Monad.Trans.Indexed.Free: liftFreeIx :: (IxMonadTransFree freeIx, IxFunctor f, Monad m) => f i j x -> freeIx f i j m x
+ Control.Monad.Trans.Indexed.Free: liftFreeIx :: (IxMonadTransFree freeIx, forall k l. Functor (f k l), Monad m) => f i j x -> freeIx f i j m x
- Control.Monad.Trans.Indexed.Free: liftFreerIx :: (IxMonadTransFree freeIx, Monad m) => f i j x -> freeIx (IxMap f) i j m x
+ Control.Monad.Trans.Indexed.Free: liftFreerIx :: (IxMonadTransFree freeIx, Monad m) => f i j x -> FreerIx freeIx f i j m x
- Control.Monad.Trans.Indexed.State: modifyIx :: Applicative m => (i -> j) -> StateIx i j m ()
+ Control.Monad.Trans.Indexed.State: modifyIx :: (IxMonadTransState t, Monad m) => (i -> j) -> t i j m ()
- Control.Monad.Trans.Indexed.State: putIx :: Applicative m => j -> StateIx i j m ()
+ Control.Monad.Trans.Indexed.State: putIx :: (IxMonadTransState t, Monad m) => j -> t i j m ()
Files
- CHANGELOG.md +5/−0
- LICENSE +1/−1
- README.md +7/−3
- indexed-transformers.cabal +96/−10
- src/Control/Monad/Trans/Indexed.hs +15/−15
- src/Control/Monad/Trans/Indexed/Codensity.hs +162/−0
- src/Control/Monad/Trans/Indexed/Cont.hs +52/−1
- src/Control/Monad/Trans/Indexed/Do.hs +4/−1
- src/Control/Monad/Trans/Indexed/Free.hs +190/−62
- src/Control/Monad/Trans/Indexed/Free/Fold.hs +0/−55
- src/Control/Monad/Trans/Indexed/Free/Wrap.hs +0/−66
- src/Control/Monad/Trans/Indexed/State.hs +58/−9
- src/Control/Monad/Trans/Indexed/Writer.hs +25/−1
- test/doctests/Doctests.hs +7/−0
- test/spec/Spec.hs +338/−0
CHANGELOG.md view
@@ -10,3 +10,8 @@ * 0.1.0.1-4 - minor fixes++* 0.2.0.0+ - added indexed codensity monad transformers+ - rewrite of free indexed monad transformers+ - doctests
LICENSE view
@@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2024, Morphism, LLC+Copyright (c) 2026, Morphism, LLC All rights reserved. Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,14 +1,18 @@ # indexed-transformers An [Atkey indexed monad](https://bentnib.org/paramnotions-jfp.pdf)-is a `Functor` [enriched category](https://ncatlab.org/nlab/show/enriched+category).+is an endo`Functor` [enriched category](https://ncatlab.org/nlab/show/enriched+category),+or [efect](https://mail.haskell.org/pipermail/haskell-cafe/2004-July/006448.html) for short. An indexed monad transformer transforms a `Monad` into an indexed monad. This library provides - a typeclass for indexed monad transformers - qualified do notation to use with them+ - a typeclass for free indexed monad transformers+ - a typeclass for state indexed monad transformers - and instances for the- - free indexed monad transformer+ - free indexed monad transformers+ - codensity indexed monad transformers - continuation indexed monad transformer- - state indexed monad transfomer+ - state indexed monad transformer - writer indexed monad transformer
indexed-transformers.cabal view
@@ -1,24 +1,25 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.36.0.+-- This file has been generated from package.yaml by hpack version 0.39.6. -- -- see: https://github.com/sol/hpack name: indexed-transformers-version: 0.1.0.4+version: 0.2.0.0 synopsis: Atkey indexed monad transformers description: Please see the README on GitHub at <https://github.com/morphismtech/indexed-transformers#readme> category: Control homepage: https://github.com/morphismtech/indexed-transformers#readme bug-reports: https://github.com/morphismtech/indexed-transformers/issues author: Eitan Chatav-maintainer: eitan@morphism.tech-copyright: 2024 Eitan Chatav+maintainer: eitan.chatav@gmail.com+copyright: 2026 Eitan Chatav license: BSD-3-Clause license-file: LICENSE build-type: Simple extra-source-files: README.md+extra-doc-files: CHANGELOG.md source-repository head@@ -28,11 +29,10 @@ library exposed-modules: Control.Monad.Trans.Indexed+ Control.Monad.Trans.Indexed.Codensity Control.Monad.Trans.Indexed.Cont Control.Monad.Trans.Indexed.Do Control.Monad.Trans.Indexed.Free- Control.Monad.Trans.Indexed.Free.Fold- Control.Monad.Trans.Indexed.Free.Wrap Control.Monad.Trans.Indexed.State Control.Monad.Trans.Indexed.Writer other-modules:@@ -44,20 +44,106 @@ default-extensions: ConstraintKinds DeriveFunctor+ DerivingStrategies FlexibleInstances GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost LambdaCase MultiParamTypeClasses PolyKinds+ QualifiedDo QuantifiedConstraints RankNTypes+ StandaloneDeriving StandaloneKindSignatures TupleSections TypeOperators+ UndecidableInstances ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints build-depends:- base >=4.7 && <5- , free- , mtl- , transformers+ base >=4.18.1.0 && <5+ , free >=5.2 && <6+ , kan-extensions >=5.2.5 && <6+ , mtl >=2.3.1 && <3+ , transformers >=0.6.1.0 && <1+ default-language: Haskell2010++test-suite doctests+ type: exitcode-stdio-1.0+ main-is: Doctests.hs+ other-modules:+ Paths_indexed_transformers+ autogen-modules:+ Paths_indexed_transformers+ hs-source-dirs:+ test/doctests+ default-extensions:+ ConstraintKinds+ DeriveFunctor+ DerivingStrategies+ FlexibleInstances+ GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ MultiParamTypeClasses+ PolyKinds+ QualifiedDo+ QuantifiedConstraints+ RankNTypes+ StandaloneDeriving+ StandaloneKindSignatures+ TupleSections+ TypeOperators+ UndecidableInstances+ ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded+ build-depends:+ base >=4.18.1.0 && <5+ , doctest-parallel >=0.3.1 && <1+ , free >=5.2 && <6+ , indexed-transformers+ , kan-extensions >=5.2.5 && <6+ , mtl >=2.3.1 && <3+ , transformers >=0.6.1.0 && <1+ default-language: Haskell2010++test-suite spec+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_indexed_transformers+ autogen-modules:+ Paths_indexed_transformers+ hs-source-dirs:+ test/spec+ default-extensions:+ ConstraintKinds+ DeriveFunctor+ DerivingStrategies+ FlexibleInstances+ GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ MultiParamTypeClasses+ PolyKinds+ QualifiedDo+ QuantifiedConstraints+ RankNTypes+ StandaloneDeriving+ StandaloneKindSignatures+ TupleSections+ TypeOperators+ UndecidableInstances+ ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints+ build-depends:+ QuickCheck >=2.14.3 && <3+ , base >=4.18.1.0 && <5+ , free >=5.2 && <6+ , hspec >=2.11.7 && <3+ , indexed-transformers+ , kan-extensions >=5.2.5 && <6+ , mtl >=2.3.1 && <3+ , transformers >=0.6.1.0 && <1 default-language: Haskell2010
src/Control/Monad/Trans/Indexed.hs view
@@ -1,6 +1,6 @@ {- | Module : Control.Monad.Trans.Indexed-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> @@ -48,7 +48,7 @@ {- | indexed analog of `<*>` - prop> (<*>) = apIx+ > prop> (<*>) = apIx -} apIx :: Monad m@@ -60,8 +60,8 @@ {- | indexed analog of `join` - prop> join = joinIx- prop> joinIx = bindIx id+ > prop> join = joinIx+ > prop> joinIx = bindIx id -} joinIx :: Monad m@@ -72,10 +72,10 @@ {- | indexed analog of `=<<` - prop> (=<<) = bindIx- prop> bindIx f x = joinIx (f <$> x)- prop> x & bindIx return = x- prop> x & bindIx f & bindIx g = x & bindIx (f & andThenIx g)+ > prop> (=<<) = bindIx+ > prop> bindIx f x = joinIx (f <$> x)+ > prop> x & bindIx return = x+ > prop> x & bindIx f & bindIx g = x & bindIx (f & andThenIx g) -} bindIx :: Monad m@@ -87,8 +87,8 @@ {- | indexed analog of flipped `>>` - prop> (>>) = flip thenIx- prop> return () & thenIx y = y+ > prop> (>>) = flip thenIx+ > prop> return () & thenIx y = y -} thenIx :: Monad m@@ -100,11 +100,11 @@ {- | indexed analog of `<=<` - prop> (<=<) = andThenIx- prop> andThenIx g f x = bindIx g (f x)- prop> f & andThenIx return = f- prop> return & andThenIx f = f- prop> f & andThenIx g & andThenIx h = f & andThenIx (g & andThenIx h)+ > prop> (<=<) = andThenIx+ > prop> andThenIx g f x = bindIx g (f x)+ > prop> f & andThenIx return = f+ > prop> return & andThenIx f = f+ > prop> f & andThenIx g & andThenIx h = f & andThenIx (g & andThenIx h) -} andThenIx :: Monad m
+ src/Control/Monad/Trans/Indexed/Codensity.hs view
@@ -0,0 +1,162 @@+{- |+Module : Control.Monad.Trans.Indexed.Codensity+Copyright : (C) 2026 Eitan Chatav+License : BSD 3-Clause License (see the file LICENSE)+Maintainer : Eitan Chatav <eitan.chatav@gmail.com>++The indexed codensity monad transformer.+-}++module Control.Monad.Trans.Indexed.Codensity+ ( CodensityIx (..)+ , lowerCodensityIx+ , liftCodensityIx+ , toCodensity+ , wrapCodensityIx+ , resetCodensityIx+ , shiftCodensityIx+ , PredensityIx (..)+ , lowerToStateIx+ , liftFromStateIx+ ) where++import Control.Applicative+import Control.Monad+import Control.Monad.Codensity+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Trans.Indexed+import Control.Monad.Trans.Indexed.State+import Data.Kind++{- |+@'CodensityIx' t@ is the indexed monad transformer generated by taking+the right Kan extension of any indexed monad transformer @t@ along itself.++This can often be more \"efficient\" to construct than @t@ itself using+repeated applications of 'bindIx',+as in `Control.Monad.Trans.Indexed.Free.ImproveFreeIx`.++See \"Asymptotic Improvement of Computations over Free Monads\" by Janis+Voigtländer for more information.++<https://www.janis-voigtlaender.eu/papers/AsymptoticImprovementOfComputationsOverFreeMonads.pdf>+-}+newtype CodensityIx t i j m a = CodensityIx+ { runCodensityIx :: forall b k. (a -> t j k m b) -> t i k m b }+ deriving Functor++{- |+This serves as the *left*-inverse (retraction) of 'liftCodensityIx'.++> prop> lowerCodensityIx . liftCodensityIx ≡ id++In general this is not a full 2-sided inverse, merely a retraction, as+@'CodensityIx' t@ is often considerably \"larger\" than @t@.+-}+lowerCodensityIx+ :: (IxMonadTrans t, Monad m)+ => CodensityIx t i j m a -> t i j m a+lowerCodensityIx (CodensityIx f) = f return++{- | Lift a computation from the argument indexed monad+to the constructed indexed monad. -}+liftCodensityIx+ :: (IxMonadTrans t, Monad m)+ => t i j m a -> CodensityIx t i j m a+liftCodensityIx m = CodensityIx $ \h -> bindIx h m++{- | Convert to `Codensity`. -}+toCodensity :: CodensityIx t i i m a -> Codensity (t i i m) a+toCodensity (CodensityIx f) = Codensity f++{- | Wrap the remainder of the 'CodensityIx' action+using the given function. -}+wrapCodensityIx+ :: (forall a k. t j k (m :: Type -> Type) a -> t i k m a) -- ^ remainder+ -> CodensityIx t i j m ()+wrapCodensityIx f = CodensityIx (\k -> f (k ()))++{- | @'resetCodensityIx' m@ delimits the continuation of any 'shiftCodensityIx' inside @m@.++> prop> resetCodensityIx (return m) = return m+-}+resetCodensityIx :: (IxMonadTrans t, Monad m) => CodensityIx t i j m a -> CodensityIx t i j m a+resetCodensityIx = liftCodensityIx . lowerCodensityIx++{- | @'shiftCodensityIx' f@ captures the continuation up to the nearest enclosing+'resetCodensityIx' and passes it to @f@:++> prop> resetCodensityIx (shiftCodensityIx f & bindIx k) = resetCodensityIx (f (lowerCodensityIx . k))+-}+shiftCodensityIx+ :: (IxMonadTrans t, Monad m)+ => (forall b k. (a -> t j k m b) -> CodensityIx t i k m b)+ -> CodensityIx t i j m a+shiftCodensityIx f = CodensityIx $ lowerCodensityIx . f++-- CodensityIx instances+instance IxMonadTrans t => IxMonadTrans (CodensityIx t) where+ joinIx (CodensityIx k) =+ CodensityIx $ \f -> k $ \(CodensityIx g) -> g f+instance i ~ j => Applicative (CodensityIx t i j m) where+ pure x = CodensityIx $ \k -> k x+ CodensityIx cf <*> CodensityIx cx =+ CodensityIx $ \ k -> cf $ \ f -> cx (k . f)+instance i ~ j => Monad (CodensityIx t i j m) where+ return = pure+ CodensityIx cx >>= k =+ CodensityIx $ \ c -> cx (\ x -> runCodensityIx (k x) c)+instance (IxMonadTrans t, i ~ j) => MonadTrans (CodensityIx t i j) where+ lift m = CodensityIx (\k -> bindIx k (lift m))+instance (i ~ j, Alternative (t i j m), IxMonadTrans t, Monad m)+ => Alternative (CodensityIx t i j m) where+ empty = liftCodensityIx empty+ x <|> y = liftCodensityIx (lowerCodensityIx x <|> lowerCodensityIx y)+instance (i ~ j, Alternative (t i j m), IxMonadTrans t, Monad m)+ => MonadPlus (CodensityIx t i j m)++{- | `PredensityIx` `ReaderT` is an efficient encoding of `StateIx`.++'lowerToStateIx' is the *left*-inverse (retraction) of 'liftFromStateIx'.++> prop> lowerToStateIx . liftFromStateIx ≡ id++In general this is not a full 2-sided inverse, merely a retraction, as+@'PredensityIx' 'ReaderT'@ is \"larger\" than `StateIx`:+it may call its continuation any number of times.+-}+newtype PredensityIx t i j m a = PredensityIx+ { runPredensityIx :: forall b. (a -> t j m b) -> t i m b }+ deriving Functor++{- | Convert to `StateIx`. -}+lowerToStateIx :: Monad m => PredensityIx ReaderT i j m a -> StateIx i j m a+lowerToStateIx (PredensityIx f) =+ StateIx . runReaderT . f $ \x -> ReaderT $ \j -> return (x, j)++{- | Convert from `StateIx`. -}+liftFromStateIx :: Monad m => StateIx i j m a -> PredensityIx ReaderT i j m a+liftFromStateIx (StateIx f) =+ PredensityIx $ \k -> ReaderT $ \i -> f i >>= \(x, j) -> runReaderT (k x) j++-- PredensityIx instances+instance (forall i. MonadTrans (t i)) => IxMonadTrans (PredensityIx t) where+ joinIx (PredensityIx k) =+ PredensityIx $ \f -> k $ \(PredensityIx g) -> g f+instance i ~ j => Applicative (PredensityIx t i j m) where+ pure x = PredensityIx $ \k -> k x+ PredensityIx cf <*> PredensityIx cx =+ PredensityIx $ \ k -> cf $ \ f -> cx (k . f)+instance i ~ j => Monad (PredensityIx t i j m) where+ return = pure+ PredensityIx cx >>= k =+ PredensityIx $ \ c -> cx (\ x -> runPredensityIx (k x) c)+instance (MonadTrans (t i), i ~ j) => MonadTrans (PredensityIx t i j) where+ lift m = PredensityIx (lift m >>=)+instance (i ~ j, Monad m) => MonadState i (PredensityIx ReaderT i j m) where+ get = getIx+ put = putIx+instance IxMonadTransState (PredensityIx ReaderT) where+ getIx = PredensityIx (ask >>=)+ putIx j = PredensityIx (\k -> withReaderT (const j) (k ()))
src/Control/Monad/Trans/Indexed/Cont.hs view
@@ -1,10 +1,14 @@ {- | Module : Control.Monad.Trans.Indexed.Cont-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> The continuation indexed monad transformer.++Delimited continuation operators are taken from Kenichi Asai and Oleg+Kiselyov's tutorial at CW 2011, [Introduction to programming with+shift and reset](http://okmij.org/ftp/continuations/#tutorial). -} module Control.Monad.Trans.Indexed.Cont@@ -23,6 +27,11 @@ import Control.Monad.Trans import Control.Monad.Trans.Indexed +{- | The continuation indexed monad transformer.+Can be used to add continuation handling to any type constructor:+the 'Monad' instance and most of the operations do not require @m@+to be a monad.+-} newtype ContIx i j m x = ContIx {runContIx :: (x -> m j) -> m i} deriving Functor instance IxMonadTrans ContIx where@@ -37,26 +46,68 @@ lift = ContIx . (>>=) instance i ~ j => MonadCont (ContIx i j m) where callCC = callCCIx +{- | The result of running a CPS computation with 'return' as the+final continuation.++> prop> evalContIx (lift m) = m+-} evalContIx :: Monad m => ContIx x j m j -> m x evalContIx c = runContIx c return +{- | Apply a function to transform the result of a continuation-passing+computation.++> prop> runContIx (mapContIx f m) = f . runContIx m+-} mapContIx :: (m i -> m j) -> ContIx i k m x -> ContIx j k m x mapContIx g (ContIx f) = ContIx $ g . f +{- | Apply a function to transform the continuation passed to a CPS+computation.++> prop> runContIx (withContIx f m) = runContIx m . f+-} withContIx :: ((y -> m k) -> x -> m j) -> ContIx i j m x -> ContIx i k m y withContIx f (ContIx g) = ContIx $ g . f +{- | @callCCIx@ (call-with-current-continuation) calls its argument+function, passing it the current continuation. It provides+an escape continuation mechanism for use with continuation+monads. Escape continuations allow one to abort the current+computation and return a value immediately. They achieve+a similar effect to 'Control.Monad.Trans.Except.throwE'+and 'Control.Monad.Trans.Except.catchE' within an+'Control.Monad.Trans.Except.ExceptT' monad. The advantage of this+function over calling 'return' is that it makes the continuation+explicit, allowing more flexibility and better control.++The standard idiom used with @callCCIx@ is to provide a lambda-expression+to name the continuation. Then calling the named continuation anywhere+within its scope will escape from the computation, even if it is many+layers deep within nested computations.+-} callCCIx :: ((x -> ContIx j k m y) -> ContIx i j m x) -> ContIx i j m x callCCIx f = ContIx $ \k -> runContIx (f (ContIx . const . k)) k +{- | @'shiftIx' f@ captures the continuation up to the nearest enclosing+'resetIx' and passes it to @f@:++> prop> resetIx (shiftIx f >>= k) = resetIx (f (evalContIx . k))+-} shiftIx :: Monad m => ((x -> m j) -> ContIx i k m k) -> ContIx i j m x shiftIx f = ContIx (evalContIx . f) +{- | @'resetIx' m@ delimits the continuation of any 'shiftIx' inside @m@.++> prop> resetIx (lift m) = lift m+-} resetIx :: Monad m => ContIx x j m j -> ContIx i i m x resetIx = lift . evalContIx +{- | Convert to `ContT`. -} toContT :: ContIx i i m x -> ContT i m x toContT (ContIx f) = ContT f +{- | Convert from `ContT`. -} fromContT :: ContT i m x -> ContIx i i m x fromContT (ContT f) = ContIx f
src/Control/Monad/Trans/Indexed/Do.hs view
@@ -1,6 +1,6 @@ {- | Module : Control.Monad.Trans.Indexed.Do-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> @@ -22,6 +22,7 @@ import qualified Control.Monad.Trans.Indexed as Ix import Prelude hiding ((>>=), (>>), fail) +{- | Indexed binding. -} (>>=) :: (Ix.IxMonadTrans t, M.Monad m) => t i j m x@@ -29,6 +30,7 @@ -> t i k m y (>>=) = flip Ix.bindIx +{- | Indexed sequencing. -} (>>) :: (Ix.IxMonadTrans t, M.Monad m) => t i j m x@@ -36,6 +38,7 @@ -> t i k m y (>>) = flip Ix.thenIx +{- | Indexed failing. -} fail :: (Ix.IxMonadTrans t, M.MonadFail m, i ~ j) => String
src/Control/Monad/Trans/Indexed/Free.hs view
@@ -1,32 +1,17 @@-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}- {- | Module : Control.Monad.Trans.Indexed.Free-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> The free indexed monad transformer.--} -module Control.Monad.Trans.Indexed.Free- ( IxMonadTransFree (liftFreeIx, hoistFreeIx, foldFreeIx), coerceFreeIx- , IxFunctor, IxMap (IxMap), liftFreerIx, hoistFreerIx, foldFreerIx- ) where--import Control.Monad.Free-import Control.Monad.Trans.Indexed-import Data.Kind+#example# -{- |-The free `IxMonadTrans` generated by an `IxFunctor`-is characterized by the `IxMonadTransFree` class-up to the isomorphism `coerceFreeIx`.+== Example -`IxMonadTransFree` and `IxMap`, the free `IxMonadTrans` and-the free `IxFunctor`, can be combined as a "freer" `IxMonadTrans`-and used as a DSL generated by primitive commands like this+Free and freer indexed monad transformers can be used as+a domain specific language generated by primitive commands like this [Conor McBride example] (https://stackoverflow.com/questions/28690448/what-is-indexed-monad). @@ -44,25 +29,19 @@ :} >>> :{-insert- :: (IxMonadTransFree freeIx, Monad m)- => DVD -> freeIx (IxMap DVDCommand) 'False 'True m ()+insert :: Monad m => DVD -> FreerIx FreeIx DVDCommand 'False 'True m () insert dvd = liftFreerIx (Insert dvd) :} >>> :{-eject- :: (IxMonadTransFree freeIx, Monad m)- => freeIx (IxMap DVDCommand) 'True 'False m DVD+eject :: Monad m => FreerIx FreeIx DVDCommand 'True 'False m DVD eject = liftFreerIx Eject :} >>> :set -XQualifiedDo >>> import qualified Control.Monad.Trans.Indexed.Do as Indexed >>> :{-swap- :: (IxMonadTransFree freeIx, Monad m)- => DVD -> freeIx (IxMap DVDCommand) 'True 'True m DVD+swap :: Monad m => DVD -> FreerIx FreeIx DVDCommand 'True 'True m DVD swap dvd = Indexed.do dvd' <- eject insert dvd@@ -71,71 +50,220 @@ >>> import Control.Monad.Trans >>> :{-printDVD :: IxMonadTransFree freeIx => freeIx (IxMap DVDCommand) 'True 'True IO ()+printDVD :: FreerIx FreeIx DVDCommand 'True 'True IO () printDVD = Indexed.do dvd <- eject insert dvd lift $ putStrLn dvd :}+-} +module Control.Monad.Trans.Indexed.Free+ ( IxMonadTransFree (..)+ , FreeIx (..)+ , improveIx, coerceFreeIx+ , FreerIx, liftFreerIx, hoistFreerIx, foldFreerIx+ , CoyonedaIx (..)+ , WrapFreeIx (..)+ , FoldFreeIx (..)+ , ImproveFreeIx (..)+ ) where++import Control.Monad+import Control.Monad.Free+import Control.Monad.Trans+import Control.Monad.Trans.Indexed+import Control.Monad.Trans.Indexed.Codensity++{- |+The free `IxMonadTrans` generated by an indexed `Functor`+is characterized by the `IxMonadTransFree` class+up to the isomorphism `coerceFreeIx`. -} class- ( forall f. IxFunctor f => IxMonadTrans (freeIx f)- , forall f m i j. (IxFunctor f, Monad m, i ~ j)+ ( forall f. (forall k l. Functor (f k l)) => IxMonadTrans (freeIx f)+ , forall f m i j. (forall k l. Functor (f k l), Monad m, i ~ j) => MonadFree (f i j) (freeIx f i j m) ) => IxMonadTransFree freeIx where+ -- | lift a computation liftFreeIx- :: (IxFunctor f, Monad m)- => f i j x+ :: (forall k l. Functor (f k l), Monad m)+ => f i j x -- ^ computation -> freeIx f i j m x+ -- | hoist a transformation hoistFreeIx- :: (IxFunctor f, IxFunctor g, Monad m)- => (forall i j x. f i j x -> g i j x)+ :: (forall k l. Functor (f k l), forall k l. Functor (g k l), Monad m)+ => (forall k l a. f k l a -> g k l a) -- ^ transformation -> freeIx f i j m x -> freeIx g i j m x+ -- | fold with a monadic transformation foldFreeIx- :: (IxFunctor f, IxMonadTrans t, Monad m)- => (forall i j x. f i j x -> t i j m x)+ :: (forall k l. Functor (f k l), IxMonadTrans t, Monad m)+ => (forall k l a. f k l a -> t k l m a) -- ^ monadic transformation -> freeIx f i j m x -> t i j m x {- |-prop> coerceFreeIx = foldFreeIx liftFreeIx-prop> id = coerceFreeIx . coerceFreeIx+> prop> coerceFreeIx = foldFreeIx liftFreeIx+> prop> id = coerceFreeIx . coerceFreeIx -} coerceFreeIx- :: (IxMonadTransFree freeIx0, IxMonadTransFree freeIx1, IxFunctor f, Monad m)- => freeIx0 f i j m x -> freeIx1 f i j m x + :: ( IxMonadTransFree freeIx0+ , IxMonadTransFree freeIx1+ , forall k l. Functor (f k l)+ , Monad m+ )+ => freeIx0 f i j m x -- ^ from free+ -> freeIx1 f i j m x -- ^ to free coerceFreeIx = foldFreeIx liftFreeIx -type IxFunctor- :: (k -> k -> Type -> Type)- -> Constraint-type IxFunctor f = forall i j. Functor (f i j)+{- | Right associate all binds in a computation that generates an indexed free monad transformer. +This can improve the asymptotic efficiency of the result, while preserving semantics.++See \"Asymptotic Improvement of Computations over Free Monads\" by Janis+Voigtländer for more information about this combinator.++<https://www.janis-voigtlaender.eu/papers/AsymptoticImprovementOfComputationsOverFreeMonads.pdf>+-}+improveIx+ :: (forall k l. Functor (f k l), Monad m)+ => (forall freeIx. IxMonadTransFree freeIx => freeIx f i j m a) -- ^ improve this+ -> FreeIx f i j m a+improveIx m = lowerCodensityIx (runImproveFreeIx m)+ {- |-`IxMap` is the free `IxFunctor`. It's a left Kan extension.-Combining `IxMonadTransFree` with `IxMap` as demonstrated in the above example,-gives the "freer" `IxMonadTrans`, modeled on this-[Oleg Kiselyov explanation]+Combining `IxMonadTransFree` with `CoyonedaIx` gives the "freer" `IxMonadTrans`,+modeled on this [Oleg Kiselyov explanation] (https://okmij.org/ftp/Computation/free-monad.html#freer).+See the [example]("Control.Monad.Trans.Indexed.Free#example"). -}-data IxMap f i j x where- IxMap :: (x -> y) -> f i j x -> IxMap f i j y-instance Functor (IxMap f i j) where- fmap g (IxMap f x) = IxMap (g . f) x+type FreerIx freeIx f = freeIx (CoyonedaIx f) +{- | `CoyonedaIx` is the free indexed `Functor`. -}+data CoyonedaIx f i j x where+ CoyonedaIx :: (x -> y) -> f i j x -> CoyonedaIx f i j y+instance Functor (CoyonedaIx f i j) where+ fmap g (CoyonedaIx f x) = CoyonedaIx (g . f) x++-- | Lift a computation to `FreerIx`. liftFreerIx :: (IxMonadTransFree freeIx, Monad m)- => f i j x -> freeIx (IxMap f) i j m x-liftFreerIx x = liftFreeIx (IxMap id x)+ => f i j x -- ^ computation+ -> FreerIx freeIx f i j m x+liftFreerIx x = liftFreeIx (CoyonedaIx id x) +-- | Hoist a transformation to `FreerIx` hoistFreerIx :: (IxMonadTransFree freeIx, Monad m)- => (forall i j x. f i j x -> g i j x)- -> freeIx (IxMap f) i j m x -> freeIx (IxMap g) i j m x-hoistFreerIx f = hoistFreeIx (\(IxMap g x) -> IxMap g (f x))+ => (forall k l a. f k l a -> g k l a) -- ^ transformation+ -> FreerIx freeIx f i j m x -> FreerIx freeIx g i j m x+hoistFreerIx f = hoistFreeIx (\(CoyonedaIx g x) -> CoyonedaIx g (f x)) +-- | Fold with a monadic transformation over `FreerIx`. foldFreerIx :: (IxMonadTransFree freeIx, IxMonadTrans t, Monad m)- => (forall i j x. f i j x -> t i j m x)- -> freeIx (IxMap f) i j m x -> t i j m x-foldFreerIx f x = foldFreeIx (\(IxMap g y) -> g <$> f y) x+ => (forall k l a. f k l a -> t k l m a) -- ^ monadic transformation+ -> FreerIx freeIx f i j m x -> t i j m x+foldFreerIx f x = foldFreeIx (\(CoyonedaIx g y) -> g <$> f y) x++-- | A helper type for `FreeIx`.+data WrapFreeIx f i j m x where+ Unwrap :: x -> WrapFreeIx f i i m x+ Wrap :: f i j (FreeIx f j k m x) -> WrapFreeIx f i k m x+instance (forall k l. Functor (f k l), Monad m)+ => Functor (WrapFreeIx f i j m) where+ fmap f = \case+ Unwrap x -> Unwrap $ f x+ Wrap fm -> Wrap $ fmap (fmap f) fm++-- | The free indexed monad transformer.+newtype FreeIx f i j m x = FreeIx {runFreeIx :: m (WrapFreeIx f i j m x)}+instance (forall k l. Functor (f k l), Monad m)+ => Functor (FreeIx f i j m) where+ fmap f (FreeIx m) = FreeIx $ fmap (fmap f) m+instance (forall k l. Functor (f k l), i ~ j, Monad m)+ => Applicative (FreeIx f i j m) where+ pure = FreeIx . pure . Unwrap+ (<*>) = apIx+instance (forall k l. Functor (f k l), i ~ j, Monad m)+ => Monad (FreeIx f i j m) where+ return = pure+ (>>=) = flip bindIx+instance (forall k l. Functor (f k l), i ~ j)+ => MonadTrans (FreeIx f i j) where+ lift = FreeIx . fmap Unwrap+instance (forall k l. Functor (f k l)) => IxMonadTrans (FreeIx f) where+ joinIx (FreeIx mm) = FreeIx $ mm >>= \case+ Unwrap (FreeIx m) -> m+ Wrap fm -> return $ Wrap $ fmap joinIx fm+instance+ ( forall k l. Functor (f k l)+ , Monad m+ , i ~ j+ ) => MonadFree (f i j) (FreeIx f i j m) where+ wrap = FreeIx . return . Wrap+instance IxMonadTransFree FreeIx where+ liftFreeIx = FreeIx . return . Wrap . fmap return+ hoistFreeIx f (FreeIx m) = FreeIx (fmap hoist_f m)+ where+ hoist_f = \case+ Unwrap x -> Unwrap x+ Wrap y -> Wrap (f (fmap (hoistFreeIx f) y))+ foldFreeIx f (FreeIx m) = bindIx foldMap_f (lift m)+ where+ foldMap_f = \case+ Unwrap x -> return x+ Wrap y -> bindIx (foldFreeIx f) (f y)++-- | The free indexed monad transformer, encoded as its `foldFreeIx` function.+newtype FoldFreeIx g i j m x = FoldFreeIx+ {runFoldFreeIx :: forall t. (IxMonadTrans t, Monad m)+ => (forall k l a. g k l a -> t k l m a) -> t i j m x}+instance (forall k l. Functor (f k l), Monad m) => Functor (FoldFreeIx f i j m) where+ fmap f (FoldFreeIx k) = FoldFreeIx $ \step -> fmap f (k step)+instance (forall k l. Functor (f k l), i ~ j, Monad m)+ => Applicative (FoldFreeIx f i j m) where+ pure x = FoldFreeIx $ const $ pure x+ (<*>) = apIx+instance (forall k l. Functor (f k l), i ~ j, Monad m)+ => Monad (FoldFreeIx f i j m) where+ return = pure+ (>>=) = flip bindIx+instance (forall k l. Functor (f k l), i ~ j)+ => MonadTrans (FoldFreeIx f i j) where+ lift m = FoldFreeIx $ const $ lift m+instance (forall k l. Functor (f k l))+ => IxMonadTrans (FoldFreeIx f) where+ joinIx (FoldFreeIx g) = FoldFreeIx $ \k -> bindIx (\(FoldFreeIx f) -> f k) (g k)+instance+ ( forall k l. Functor (f k l)+ , Monad m+ , i ~ j+ ) => MonadFree (f i j) (FoldFreeIx f i j m) where+ wrap = join . liftFreeIx+instance IxMonadTransFree FoldFreeIx where+ liftFreeIx m = FoldFreeIx $ \k -> k m+ hoistFreeIx f (FoldFreeIx k) = FoldFreeIx $ \g -> k (g . f)+ foldFreeIx f (FoldFreeIx k) = k f++-- | A helper type for `improveIx`.+newtype ImproveFreeIx f i j m a = ImproveFreeIx+ { runImproveFreeIx :: CodensityIx (FreeIx f) i j m a }+deriving newtype instance Functor (ImproveFreeIx f i j m)+deriving newtype instance i ~ j => Applicative (ImproveFreeIx f i j m)+deriving newtype instance i ~ j => Monad (ImproveFreeIx f i j m)+deriving newtype instance (forall k l. Functor (f k l), i ~ j) => MonadTrans (ImproveFreeIx f i j)+deriving newtype instance (forall k l. Functor (f k l)) => IxMonadTrans (ImproveFreeIx f)+instance+ ( forall k l. Functor (f k l)+ , Monad m+ , i ~ j+ ) => MonadFree (f i j) (ImproveFreeIx f i j m) where+ wrap t = ImproveFreeIx $ CodensityIx $ \h ->+ joinIx (liftFreeIx (fmap (\p -> runCodensityIx (runImproveFreeIx p) h) t))+instance IxMonadTransFree ImproveFreeIx where+ liftFreeIx = ImproveFreeIx . liftCodensityIx . liftFreeIx+ hoistFreeIx f+ = ImproveFreeIx . liftCodensityIx+ . hoistFreeIx f+ . lowerCodensityIx . runImproveFreeIx+ foldFreeIx f = foldFreeIx f . lowerCodensityIx . runImproveFreeIx
− src/Control/Monad/Trans/Indexed/Free/Fold.hs
@@ -1,55 +0,0 @@-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}--{- |-Module : Control.Monad.Trans.Indexed.Free.Fold-Copyright : (C) 2024 Eitan Chatav-License : BSD 3-Clause License (see the file LICENSE)-Maintainer : Eitan Chatav <eitan.chatav@gmail.com>--An instance of the free indexed monad transformer encoded as `foldFreeIx`.--}--module Control.Monad.Trans.Indexed.Free.Fold- ( FreeIx (..)- ) where--import Control.Monad-import Control.Monad.Free-import Control.Monad.Trans-import Control.Monad.Trans.Indexed-import Control.Monad.Trans.Indexed.Free--{- |-`FreeIx` is the free indexed monad transformer encoded as its `foldFreeIx`.--prop> foldFreeIx f freeIx = runFreeIx freeIx f--}-newtype FreeIx g i j m x = FreeIx- {runFreeIx :: forall t. (IxMonadTrans t, Monad m)- => (forall i j x. g i j x -> t i j m x) -> t i j m x}-instance (IxFunctor f, Monad m) => Functor (FreeIx f i j m) where- fmap f (FreeIx k) = FreeIx $ \step -> fmap f (k step)-instance (IxFunctor f, i ~ j, Monad m)- => Applicative (FreeIx f i j m) where- pure x = FreeIx $ const $ pure x- (<*>) = apIx-instance (IxFunctor f, i ~ j, Monad m)- => Monad (FreeIx f i j m) where- return = pure- (>>=) = flip bindIx-instance (IxFunctor f, i ~ j)- => MonadTrans (FreeIx f i j) where- lift m = FreeIx $ const $ lift m-instance IxFunctor f- => IxMonadTrans (FreeIx f) where- joinIx (FreeIx g) = FreeIx $ \k -> bindIx (\(FreeIx f) -> f k) (g k)-instance- ( IxFunctor f- , Monad m- , i ~ j- ) => MonadFree (f i j) (FreeIx f i j m) where- wrap = join . liftFreeIx-instance IxMonadTransFree FreeIx where- liftFreeIx m = FreeIx $ \k -> k m- hoistFreeIx f (FreeIx k) = FreeIx $ \g -> k (g . f)- foldFreeIx f (FreeIx k) = k f
− src/Control/Monad/Trans/Indexed/Free/Wrap.hs
@@ -1,66 +0,0 @@-{- |-Module : Control.Monad.Trans.Indexed.Free.Wrap-Copyright : (C) 2024 Eitan Chatav-License : BSD 3-Clause License (see the file LICENSE)-Maintainer : Eitan Chatav <eitan.chatav@gmail.com>--An instance of the free indexed monad transformer.--}--module Control.Monad.Trans.Indexed.Free.Wrap- ( FreeIx (..)- , WrapIx (..)- ) where--import Control.Monad.Free-import Control.Monad.Trans-import Control.Monad.Trans.Indexed-import Control.Monad.Trans.Indexed.Free--data WrapIx f i j m x where- Unwrap :: x -> WrapIx f i i m x- Wrap :: f i j (FreeIx f j k m x) -> WrapIx f i k m x-instance (IxFunctor f, Monad m)- => Functor (WrapIx f i j m) where- fmap f = \case- Unwrap x -> Unwrap $ f x- Wrap fm -> Wrap $ fmap (fmap f) fm--newtype FreeIx f i j m x = FreeIx {runFreeIx :: m (WrapIx f i j m x)}-instance (IxFunctor f, Monad m)- => Functor (FreeIx f i j m) where- fmap f (FreeIx m) = FreeIx $ fmap (fmap f) m-instance (IxFunctor f, i ~ j, Monad m)- => Applicative (FreeIx f i j m) where- pure = FreeIx . pure . Unwrap- (<*>) = apIx-instance (IxFunctor f, i ~ j, Monad m)- => Monad (FreeIx f i j m) where- return = pure- (>>=) = flip bindIx-instance (IxFunctor f, i ~ j)- => MonadTrans (FreeIx f i j) where- lift = FreeIx . fmap Unwrap-instance IxFunctor f- => IxMonadTrans (FreeIx f) where- joinIx (FreeIx mm) = FreeIx $ mm >>= \case- Unwrap (FreeIx m) -> m- Wrap fm -> return $ Wrap $ fmap joinIx fm-instance- ( IxFunctor f- , Monad m- , i ~ j- ) => MonadFree (f i j) (FreeIx f i j m) where- wrap = FreeIx . return . Wrap-instance IxMonadTransFree FreeIx where- liftFreeIx = FreeIx . return . Wrap . fmap return- hoistFreeIx f (FreeIx m) = FreeIx (fmap hoist_f m)- where- hoist_f = \case- Unwrap x -> Unwrap x- Wrap y -> Wrap (f (fmap (hoistFreeIx f) y))- foldFreeIx f (FreeIx m) = bindIx foldMap_f (lift m)- where- foldMap_f = \case- Unwrap x -> return x- Wrap y -> bindIx (foldFreeIx f) (f y)
src/Control/Monad/Trans/Indexed/State.hs view
@@ -1,6 +1,6 @@ {- | Module : Control.Monad.Trans.Indexed.State-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> @@ -11,15 +11,32 @@ ( StateIx (..) , evalStateIx , execStateIx- , modifyIx- , putIx , toStateT , fromStateT+ , IxMonadTransState (..), modifyIx ) where +import Control.Monad.Reader import Control.Monad.State import Control.Monad.Trans.Indexed+import Control.Monad.Trans.Indexed.Do qualified as Indexed +{- | An indexed state transformer monad parameterized by:++ * @i@ - The initial state.++ * @j@ - The final state.++ * @m@ - The inner monad.++The 'return' function leaves the state unchanged, while 'bindIx' uses+the final state of the first computation as the initial state of+the second.++An efficient encoding of `StateIx`, up to the retraction+`Control.Monad.Trans.Indexed.Codensity.lowerToStateIx`, is+`Control.Monad.Trans.Indexed.Codensity.PredensityIx` `ReaderT`.+-} newtype StateIx i j m x = StateIx { runStateIx :: i -> m (x, j)} deriving Functor instance IxMonadTrans StateIx where@@ -37,20 +54,52 @@ instance (i ~ j, Monad m) => MonadState i (StateIx i j m) where state f = StateIx (return . f) +{- | Evaluate a state computation with the given initial state+and return the final value, discarding the final state.+-} evalStateIx :: Monad m => StateIx i j m x -> i -> m x evalStateIx m i = fst <$> runStateIx m i +{- | Evaluate a state computation with the given initial state+and return the final state, discarding the final value.+-} execStateIx :: Monad m => StateIx i j m x -> i -> m j execStateIx m i = snd <$> runStateIx m i -modifyIx :: Applicative m => (i -> j) -> StateIx i j m ()-modifyIx f = StateIx $ \i -> pure ((), f i)--putIx :: Applicative m => j -> StateIx i j m ()-putIx j = modifyIx (\ _ -> j)-+{- | Convert to `StateT`. -} toStateT :: StateIx i i m x -> StateT i m x toStateT (StateIx f) = StateT f +{- | Convert from `StateT`. -} fromStateT :: StateT i m x -> StateIx i i m x fromStateT (StateT f) = StateIx f++{- | Minimal definition is either both of @getIx@ and @putIx@ or just @stateIx@ -}+class+ ( IxMonadTrans t+ , forall i m. Monad m => MonadState i (t i i m)+ ) => IxMonadTransState t where+ {-# MINIMAL stateIx | getIx, putIx #-}+ -- | Return the state from the internals of the monad.+ getIx :: Monad m => t i i m i+ getIx = stateIx (\i -> return (i,i))+ -- | Replace the state inside the monad.+ putIx :: Monad m => j -> t i j m ()+ putIx i = stateIx (\_ -> return ((),i))+ -- | Embed a state action into the monad.+ stateIx :: Monad m => (i -> m (x,j)) -> t i j m x+ stateIx f = Indexed.do+ i <- getIx+ ~(x, j) <- lift (f i)+ putIx j+ return x+instance IxMonadTransState StateIx where+ stateIx = StateIx++{- | @'modifyIx' f@ is an action that updates the state to the result of+applying @f@ to the current state.++> prop> modifyIx f = getIx & bindIx (putIx . f)+-}+modifyIx :: (IxMonadTransState t, Monad m) => (i -> j) -> t i j m ()+modifyIx f = stateIx (\i -> return ((), f i))
src/Control/Monad/Trans/Indexed/Writer.hs view
@@ -1,6 +1,6 @@ {- | Module : Control.Monad.Trans.Indexed.Writer-Copyright : (C) 2024 Eitan Chatav+Copyright : (C) 2026 Eitan Chatav License : BSD 3-Clause License (see the file LICENSE) Maintainer : Eitan Chatav <eitan.chatav@gmail.com> @@ -24,6 +24,15 @@ import Control.Monad.Trans import Control.Monad.Trans.Indexed +{- | An indexed writer monad parameterized by:++ * @w@ - the output to accumulate.++ * @m@ - The inner monad.++The 'return' function produces the output 'id', while `bindIx`+combines the outputs of the subcomputations using '>>>'.+-} newtype WriterIx w i j m x = WriterIx {runWriterIx :: m (x, w i j)} deriving Functor @@ -47,26 +56,35 @@ x <- m return (x, id) +{- | Extract the return value from a writer computation. -} evalWriterIx :: Monad m => WriterIx w i j m x -> m x evalWriterIx (WriterIx m) = fst <$> m +{- | Extract the output from a writer computation. -} execWriterIx :: Monad m => WriterIx w i j m x -> m (w i j) execWriterIx (WriterIx m) = snd <$> m +{- | Map both the return value and output of a computation using+the given function. -} mapWriterIx :: (m (x, w i j) -> n (y, q i j)) -> WriterIx w i j m x -> WriterIx q i j n y mapWriterIx f m = WriterIx $ f (runWriterIx m) +{- | @'tellIx' w@ is an action that produces the output @w@. -} tellIx :: Monad m => w i j -> WriterIx w i j m () tellIx w = WriterIx (return ((), w)) +{- | @'listenIx' m@ is an action that executes the action @m@ and adds its+output to the value of the computation. -} listenIx :: Monad m => WriterIx w i j m x -> WriterIx w i j m (x, w i j) listenIx (WriterIx m) = WriterIx $ do (x, w) <- m return ((x, w),w) +{- | @'listensIx' f m@ is an action that executes the action @m@ and adds+the result of applying @f@ to the output to the value of the computation. -} listensIx :: Monad m => (w i j -> y)@@ -76,6 +94,9 @@ (x, w) <- m return ((x, f w), w) +{- | @'passIx' m@ is an action that executes the action @m@, which returns+a value and a function, and returns the value, applying the function+to the output. -} passIx :: Monad m => WriterIx w i j m (x, w i j -> q i j)@@ -84,6 +105,9 @@ ((x, f), w) <- m return (x, f w) +{- | @'censorIx' f m@ is an action that executes the action @m@ and+applies the function @f@ to its output, leaving the return value+unchanged. -} censorIx :: Monad m => (w i j -> w i j) -> WriterIx w i j m x -> WriterIx w i j m x censorIx f (WriterIx m) = WriterIx $ do (x, w) <- m
+ test/doctests/Doctests.hs view
@@ -0,0 +1,7 @@+module Main (main) where++import System.Environment (getArgs)+import Test.DocTest (mainFromCabal)++main :: IO ()+main = mainFromCabal "indexed-transformers" =<< getArgs
+ test/spec/Spec.hs view
@@ -0,0 +1,338 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Main (main) where++import Control.Category (Category, (>>>))+import Control.Category qualified as Category+import Control.Monad+import Control.Monad.Codensity (lowerCodensity)+import Control.Monad.Cont (runContT)+import Control.Monad.Free (wrap)+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Trans.Indexed+import Control.Monad.Trans.Indexed.Codensity+import Control.Monad.Trans.Indexed.Cont+import Control.Monad.Trans.Indexed.Do qualified as Indexed+import Control.Monad.Trans.Indexed.Free+import Control.Monad.Trans.Indexed.State+import Control.Monad.Trans.Indexed.Writer+import Control.Monad.Writer (Writer, runWriter, tell)+import Data.Foldable+import Data.Kind+import Data.Proxy+import Test.Hspec+import Test.QuickCheck++type W = Writer [Int]++w :: ([Int], x) -> W x+w (xs, x) = tell xs >> return x++data Prog+ = Done Int+ | Tell Int Prog+ | Op Int+ | Bind Prog (Fun Int Prog)+ deriving Show++instance Arbitrary Prog where+ arbitrary = sized go+ where+ go 0 = oneof [Done <$> arbitrary, Op <$> arbitrary]+ go n = oneof+ [ Done <$> arbitrary+ , Op <$> arbitrary+ , Tell <$> arbitrary <*> go (n - 1)+ , Bind <$> go (n `div` 2) <*> resize (n `div` 2) arbitrary+ ]+ shrink = \case+ Done _ -> []+ Op n -> [Done n]+ Tell _ p -> [p]+ Bind p f -> [p] ++ [Bind p' f | p' <- shrink p]++interp :: IxMonadTrans t => (Int -> t Int Int W Int) -> Prog -> t Int Int W Int+interp op = \case+ Done n -> pure n+ Tell n p -> thenIx (interp op p) (lift (tell [n]))+ Op n -> op n+ Bind p f -> bindIx (interp op . applyFun f) (interp op p)++stateOp :: IxMonadTransState t => Int -> t Int Int W Int+stateOp n = stateIx $ \s -> tell [s] >> return (s, s + n)++observeState :: StateIx Int Int W Int -> Int -> [Int]+observeState m s = let ((x, s'), xs) = runWriter (runStateIx m s) in xs ++ [x, s']++type Cmd :: Type -> Type -> Type -> Type+data Cmd i j x where+ Cmd :: Int -> Cmd Int Int Int++runCmd :: Cmd i j x -> StateIx i j W x+runCmd (Cmd n) = stateOp n++newtype Log i j = Log [Int]+ deriving (Eq, Show)+instance Category Log where+ id = Log []+ Log ys . Log xs = Log (xs ++ ys)++data Subject = forall t. IxMonadTrans t+ => Subject String (Int -> t Int Int W Int) (t Int Int W Int -> Int -> [Int])++data FreeSubject = forall (freeIx :: (Type -> Type -> Type -> Type) -> Type -> Type -> (Type -> Type) -> Type -> Type).+ IxMonadTransFree freeIx => FreeSubject String (Proxy freeIx)++freeSubjects :: [FreeSubject]+freeSubjects =+ [ FreeSubject "FreeIx" (Proxy @FreeIx)+ , FreeSubject "FoldFreeIx" (Proxy @FoldFreeIx)+ , FreeSubject "ImproveFreeIx" (Proxy @ImproveFreeIx)+ ]++freeProg :: IxMonadTransFree freeIx => Prog -> FreerIx freeIx Cmd Int Int W Int+freeProg = interp (liftFreerIx . Cmd)++observeFree :: IxMonadTransFree freeIx => FreerIx freeIx Cmd Int Int W Int -> Int -> [Int]+observeFree = observeState . foldFreerIx runCmd++stateSubjects :: [Subject]+stateSubjects =+ [ Subject "StateIx" stateOp observeState+ , Subject "PredensityIx ReaderT" stateOp (observeState . lowerToStateIx)+ , Subject "CodensityIx StateIx"+ (liftCodensityIx . stateOp) (observeState . lowerCodensityIx)+ , Subject "CodensityIx FreeIx"+ (liftCodensityIx . liftFreerIx . Cmd)+ (observeFree @FreeIx . lowerCodensityIx)+ ] +++ [ Subject name (liftFreerIx . Cmd) (observeFree @freeIx)+ | FreeSubject name (_ :: Proxy freeIx) <- freeSubjects+ ]++otherSubjects :: [Subject]+otherSubjects =+ [ Subject "WriterIx"+ (\n -> thenIx (pure (n + 1)) (tellIx (Log [n])))+ (\m _ ->+ let ((x, Log ys), xs) = runWriter (runWriterIx m)+ in [length xs] ++ xs ++ ys ++ [x])+ , Subject "ContIx"+ (\n -> ContIx $ \k -> (+ n) <$> k n)+ (\m s ->+ let (x, xs) = runWriter (runContIx m (\y -> tell [y] >> return (2 * y + s)))+ in xs ++ [x])+ ]++laws :: Subject -> Spec+laws (Subject name op run) = describe name $ do+ let+ p = interp op+ (m0 =~= m1) s = run m0 s === run m1 s+ it "left identity" $ property $ \(x :: Int) (Fn f) ->+ bindIx (p . f) (pure x) =~= p (f x)+ it "right identity" $ property $ \m ->+ bindIx pure (p m) =~= p m+ it "associativity" $ property $ \m (Fn f) (Fn g) ->+ bindIx (p . g) (bindIx (p . f) (p m))+ =~= bindIx (andThenIx (p . g) (p . f)) (p m)+ it "joinIx" $ property $ \m (Fn f) ->+ joinIx (p . f <$> p m) =~= bindIx (p . f) (p m)+ it "(>>=) = flip bindIx" $ property $ \m (Fn f) ->+ (p m >>= p . f) =~= bindIx (p . f) (p m)+ it "(<*>) = apIx" $ property $ \m0 m1 (Fn2 f) ->+ (f <$> p m0 <*> p m1) =~= apIx (f <$> p m0) (p m1)+ it "(>>) = flip thenIx" $ property $ \m0 m1 ->+ (p m0 >> p m1) =~= thenIx (p m1) (p m0)+ it "fmap" $ property $ \m (Fn (f :: Int -> Int)) ->+ (f <$> p m) =~= bindIx (pure . f) (p m)+ it "lift . return = return" $ property $ \(x :: Int) ->+ lift (return x) =~= pure x+ it "lift (m >>= f) = lift m >>= lift . f" $ property $ \(m :: ([Int], Int)) (Fn (f :: Int -> ([Int], Int))) ->+ lift (w m >>= w . f) =~= (lift (w m) >>= lift . w . f)++stateLaws+ :: forall t. IxMonadTransState t+ => String+ -> (forall i j x. t i j W x -> StateIx i j W x)+ -> Spec+stateLaws name toState = describe name $ do+ let+ run :: t i j W x -> i -> ((x, j), [Int])+ run m s = runWriter (runStateIx (toState m) s)+ it "getIx" $ property $ \(s :: Int) ->+ run getIx s === ((s, s), [])+ it "putIx" $ property $ \(s :: Int) (s' :: String) ->+ run (putIx s') s === (((), s'), [])+ it "stateIx" $ property $ \(Fn (f :: Int -> ([Int], (Bool, String)))) s ->+ run (stateIx (w . f)) s === runWriter (w (f s))+ it "modifyIx" $ property $ \(Fn (f :: Int -> String)) s ->+ run (modifyIx f) s === (((), f s), [])+ it "get then put" $ property $ \(s :: Int) ->+ run (bindIx putIx getIx) s === run (pure ()) s+ it "put then get" $ property $ \(s :: Int) (s' :: String) ->+ run (thenIx getIx (putIx s')) s === run (thenIx (pure s') (putIx s')) s+ it "put then put" $ property $ \(s :: Int) (s' :: Bool) (s'' :: String) ->+ run (thenIx (putIx s'') (putIx s')) s === run (putIx s'') s+ it "MonadState" $ property $ \(Fn (f :: Int -> Int)) s ->+ run (state (\x -> (x, f x))) s === ((s, f s), [])+ it "Indexed.do" $ property $ \(s :: Int) (s' :: String) ->+ run+ ( Indexed.do+ putIx s'+ x <- getIx+ putIx (length x)+ return x+ ) s+ === ((s', length s'), [])++predensitySpec :: Spec+predensitySpec = describe "PredensityIx ReaderT" $ do+ it "lowerToStateIx . liftFromStateIx = id" $ property $+ \(Fn (f :: Int -> ([Int], (Bool, String)))) s ->+ let m = StateIx (w . f)+ in runWriter (runStateIx (lowerToStateIx (liftFromStateIx m)) s)+ === runWriter (runStateIx m s)+ it "liftFromStateIx . lowerToStateIx = id on stateIx terms" $ property $+ \prog (Fn2 (k :: Int -> Int -> ([Int], Int))) s ->+ let+ m = interp stateOp prog+ run m' = runWriter (runReaderT (runPredensityIx m' (\x -> ReaderT (w . k x))) s)+ in run (liftFromStateIx (lowerToStateIx m)) === run m++codensitySpec :: Spec+codensitySpec = describe "CodensityIx StateIx" $ do+ let p = interp (liftCodensityIx . stateOp)+ it "lowerCodensityIx . liftCodensityIx = id" $ property $ \prog s ->+ let m = interp stateOp prog+ in observeState (lowerCodensityIx (liftCodensityIx m)) s === observeState m s+ it "resetCodensityIx" $ property $ \prog s ->+ observeState (lowerCodensityIx (resetCodensityIx (p prog))) s+ === observeState (lowerCodensityIx (p prog)) s+ it "toCodensity" $ property $ \prog s ->+ observeState (lowerCodensity (toCodensity (p prog))) s+ === observeState (lowerCodensityIx (p prog)) s+ it "wrapCodensityIx" $ property $ \(s :: Int) (s' :: String) ->+ let m0 = lowerCodensityIx (wrapCodensityIx (\m -> thenIx m (putIx s'))) :: StateIx Int String W ()+ in runWriter (runStateIx m0 s) === runWriter (runStateIx (putIx s') s)+ it "shiftCodensityIx" $ property $ \(x :: Int) (n :: Int) (Fn f) s ->+ observeState+ (lowerCodensityIx+ (shiftCodensityIx (\k -> liftCodensityIx (thenIx (k x) (modifyIx (+ n)))) >>= p . f))+ s+ === observeState (thenIx (lowerCodensityIx (p (f x))) (modifyIx (+ n))) s++freeSpec :: FreeSubject -> Spec+freeSpec (FreeSubject name (_ :: Proxy freeIx)) = describe name $ do+ forM_ freeSubjects $ \(FreeSubject name' (_ :: Proxy freeIx')) ->+ it ("coerceFreeIx to " <> name') $ property $ \prog s ->+ observeFree @freeIx' (coerceFreeIx (freeProg @freeIx prog)) s+ === observeFree @freeIx (freeProg prog) s+ it "foldFreeIx f . liftFreeIx = f" $ property $ \n s ->+ observeFree @freeIx (liftFreerIx (Cmd n)) s === observeState (runCmd (Cmd n)) s+ it "hoistFreerIx" $ property $ \prog s ->+ let double :: Cmd i j x -> Cmd i j x+ double (Cmd n) = Cmd (2 * n)+ in observeFree (hoistFreerIx double (freeProg @freeIx prog)) s+ === observeState (foldFreerIx (runCmd . double) (freeProg @freeIx prog)) s+ it "wrap" $ property $ \n (Fn f) s ->+ observeFree @freeIx (wrap (CoyonedaIx (freeProg . f) (Cmd n))) s+ === observeFree @freeIx (bindIx (freeProg . f) (liftFreerIx (Cmd n))) s+ it "improveIx" $ property $ \prog s ->+ observeFree (improveIx (freeProg prog)) s === observeFree @freeIx (freeProg prog) s++contSpec :: Spec+contSpec = describe "ContIx" $ do+ let+ p :: Prog -> ContIx Int Int W Int+ p = interp (\n -> ContIx $ \k -> (+ n) <$> k n)+ eval = runWriter . evalContIx+ it "callCCIx" $ property $ \prog (x :: Int) ->+ eval (callCCIx (\k -> thenIx (p prog) (k x))) === eval (pure x)+ it "shiftIx" $ property $ \(x :: Int) (Fn g) ->+ eval (g <$> shiftIx (\k -> lift (k x >>= k))) === eval (pure (g (g x)))+ it "resetIx" $ property $ \prog ->+ eval (resetIx (p prog) :: ContIx Int Int W Int) === eval (p prog)+ it "withContIx" $ property $ \prog (Fn (f :: Int -> Int)) ->+ eval (withContIx (\k -> k . f) (p prog)) === eval (f <$> p prog)+ it "toContT . fromContT" $ property $ \prog ->+ runWriter (runContT (toContT (fromContT (toContT (p prog)))) return)+ === eval (p prog)++writerSpec :: Spec+writerSpec = describe "WriterIx" $ do+ let+ run :: WriterIx Log i j W x -> ((x, Log i j), [Int])+ run = runWriter . runWriterIx+ it "tellIx" $ property $ \xs ys ->+ run (thenIx (tellIx (Log ys)) (tellIx (Log xs)) :: WriterIx Log Int Bool W ())+ === run (tellIx (Log xs >>> Log ys))+ it "listenIx" $ property $ \xs (x :: Int) ->+ let m = thenIx (pure x) (tellIx (Log xs)) :: WriterIx Log Int Bool W Int+ in run (listenIx m) === (((x, Log xs), Log xs), [])+ it "listensIx" $ property $ \xs (x :: Int) ->+ let m = thenIx (pure x) (tellIx (Log xs)) :: WriterIx Log Int Bool W Int+ in run (listensIx (\(Log ys) -> sum ys) m) === (((x, sum xs), Log xs), [])+ it "censorIx" $ property $ \xs (Fn f) ->+ run (censorIx (\(Log ys) -> Log (f ys)) (tellIx (Log xs) :: WriterIx Log Int Bool W ()))+ === (((), Log (f xs)), [])+ it "passIx" $ property $ \xs (Fn f) (x :: Int) ->+ run (passIx (WriterIx (return ((x, \(Log ys) -> Log (f ys)), Log xs))) :: WriterIx Log Int Bool W Int)+ === ((x, Log (f xs)), [])+ it "evalWriterIx and execWriterIx" $ property $ \xs (x :: Int) ->+ let m = thenIx (pure x) (tellIx (Log xs)) :: WriterIx Log Int Bool W Int+ in (runWriter (evalWriterIx m), runWriter (execWriterIx m)) === ((x, []), (Log xs, []))++categorySpec :: Spec+categorySpec = describe "Indexed StateIx" $ do+ let+ st :: Fun i ([Int], ([Int], j)) -> Indexed StateIx W [Int] i j+ st (Fn f) = Indexed (StateIx (w . f))+ run :: Indexed StateIx W [Int] i j -> i -> (([Int], j), [Int])+ run m s = runWriter (runStateIx (runIndexed m) s)+ it "left identity" $ property $ \(f :: Fun Int ([Int], ([Int], String))) s ->+ run (Category.id Category.. st f) s === run (st f) s+ it "right identity" $ property $ \(f :: Fun Int ([Int], ([Int], String))) s ->+ run (st f Category.. Category.id) s === run (st f) s+ it "associativity" $ property $+ \(f :: Fun Int ([Int], ([Int], String)))+ (g :: Fun String ([Int], ([Int], Bool)))+ (h :: Fun Bool ([Int], ([Int], Int)))+ s ->+ run ((st h Category.. st g) Category.. st f) s+ === run (st h Category.. (st g Category.. st f)) s++stateSpec :: Spec+stateSpec = describe "StateIx" $ do+ it "toStateT" $ property $ \prog s ->+ let m = interp stateOp prog+ in runWriter (runStateT (toStateT m) s) === runWriter (runStateIx m s)+ it "fromStateT . toStateT = id" $ property $ \prog s ->+ let m = interp stateOp prog+ in observeState (fromStateT (toStateT m)) s === observeState m s+ it "evalStateIx and execStateIx" $ property $ \prog s ->+ let m = interp stateOp prog+ ((x, s'), xs) = runWriter (runStateIx m s)+ in (runWriter (evalStateIx m s), runWriter (execStateIx m s)) === ((x, xs), (s', xs))++main :: IO ()+main = hspec $ do+ describe "IxMonadTrans laws" $+ mapM_ laws (stateSubjects ++ otherSubjects)+ describe "state transformers agree with StateIx" $+ forM_ stateSubjects $ \(Subject name op run) ->+ it name $ property $ \prog s ->+ run (interp op prog) s === observeState (interp stateOp prog) s+ describe "IxMonadTransState laws" $ do+ stateLaws "StateIx" id+ stateLaws "PredensityIx ReaderT" lowerToStateIx+ predensitySpec+ codensitySpec+ describe "IxMonadTransFree" $ traverse_ freeSpec freeSubjects+ contSpec+ writerSpec+ categorySpec+ stateSpec