packages feed

heftia-0.2.0.0: src/Control/Monad/Freer/Church.hs

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.

{- |
Copyright   :  (c) 2023 Yamada Ryo
License     :  MPL-2.0 (see the file LICENSE)
Maintainer  :  ymdfield@outlook.jp
Stability   :  experimental
Portability :  portable

A Church-encoded Freer monad.
-}
module Control.Monad.Freer.Church where

import Control.Effect (type (~>))
import Control.Freer (Freer, interpretFreer, liftIns, retractFreer, transformFreer)
import Control.Monad.Cont (Cont, ContT (ContT), runCont)
import Control.Monad.Freer (MonadFreer, interpretFreerK)
import Control.Monad.Identity (Identity (Identity), runIdentity)
import Control.Monad.Trans.Free.Church (FT (FT), retract, transFT)

-- | A Church encoded Freer monad.
newtype FreerChurch f a = FreerChurch {unFreerChurch :: FT f Identity a}
    deriving newtype
        ( Functor
        , Applicative
        , Monad
        , Eq
        , Ord
        )
    deriving stock (Foldable, Traversable)

liftInsChurch :: ins a -> FreerChurch ins a
liftInsChurch e = FreerChurch $ FT \k f -> f k e
{-# INLINE liftInsChurch #-}

interpretChurch :: Monad m => (ins ~> m) -> FreerChurch ins a -> m a
interpretChurch i = retract . transFT i . unFreerChurch
{-# INLINE interpretChurch #-}

interpretChurchK :: (e ~> Cont r) -> FreerChurch e ~> Cont r
interpretChurchK i (FreerChurch (FT f)) =
    ContT \k -> f k \k' e -> Identity $ runCont (i e) (runIdentity . k')

instance Freer Monad FreerChurch where
    liftIns = liftInsChurch
    interpretFreer = interpretChurch
    retractFreer = retract . unFreerChurch
    transformFreer phi = FreerChurch . transFT phi . unFreerChurch
    {-# INLINE liftIns #-}
    {-# INLINE interpretFreer #-}
    {-# INLINE retractFreer #-}
    {-# INLINE transformFreer #-}

instance MonadFreer Monad FreerChurch where
    interpretFreerK = interpretChurchK
    {-# INLINE interpretFreerK #-}