packages feed

indexed-transformers-0.1.0.0: src/Control/Monad/Trans/Indexed/Free/Fold.hs

{-# 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