functor-monad-0.1.1.0: src/FMonad/FreeT.hs
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
-- | Another way to make 'FreeT' an instance of 'FMonad'
--
-- 'FreeT' can be 'FMonad' in two different ways. There is already an instance:
--
-- @
-- instance Functor f => FMonad (FreeT f) where
-- fpure :: Functor m => m ~> FreeT f m
-- fbind :: (Functor m, Functor n) => (m ~> FreeT f n) -> (FreeT f m ~> FreeT f n)
-- @
--
-- In addition to this standard instance, @FreeT f m@ have @FMonad@-like structure by treating
-- @f@ as the parameter while fixing @m@ to some arbitrary @Monad@.
--
-- @
-- 'fpureFst' :: (Monad m) => (Functor f) => f ~> FreeT f m
-- 'fbindFst' :: (Monad m) => (Functor f, Functor g) => (f ~> FreeT g m) -> (FreeT f m ~> FreeT g m)
-- @
--
-- This module provides a newtype wrapper 'FreeT'' to use these as a real @FMonad@
-- instance.
module FMonad.FreeT
( FreeT' (..), liftM', fpureFst, fbindFst )
where
import Control.Applicative (Alternative)
import Control.Monad (MonadPlus)
import Control.Monad.Trans.Free
import Control.Monad.Trans.Free.Extra
import Data.Functor.Classes
import FMonad
-- | @FreeT'@ is a @FreeT@, but with the order of its arguments flipped.
--
-- @
-- FreeT' m f a ≡ FreeT f m a
-- @
newtype FreeT' m f b = WrapFreeT' {unwrapFreeT' :: FreeT f m b}
deriving
(Functor)
via (FreeT f m)
deriving
( Applicative,
Alternative,
Monad,
MonadPlus,
Foldable,
Eq1,
Ord1,
Show1,
Read1
)
via (FreeT f m)
deriving
(Show, Read, Eq, Ord)
via (FreeT f m b)
-- | Lift of the Monad side.
liftM' :: Functor m => m a -> FreeT' m f a
liftM' = WrapFreeT' . inr
-- | @fpure@ to the first parameter of @FreeT@
fpureFst :: (Monad m) => (Functor f) => f ~> FreeT f m
fpureFst = liftF
-- | @fbind@ to the first parameter of @FreeT@
fbindFst :: (Monad m) => (Functor f, Functor g) => (f ~> FreeT g m) -> (FreeT f m ~> FreeT g m)
fbindFst k = eitherFreeT_ k inr
instance (Traversable f, Traversable m) => Traversable (FreeT' f m) where
traverse f (WrapFreeT' mx) = WrapFreeT' <$> traverseFreeT_ f mx
instance Functor m => FFunctor (FreeT' m) where
ffmap f = WrapFreeT' . transFreeT_ f . unwrapFreeT'
instance Monad m => FMonad (FreeT' m) where
fpure :: forall g. Functor g => g ~> FreeT' m g
fpure = WrapFreeT' . fpureFst
fbind :: forall g h a. (Functor g, Functor h) => (g ~> FreeT' m h) -> FreeT' m g a -> FreeT' m h a
fbind k = WrapFreeT' . fbindFst (unwrapFreeT' . k) . unwrapFreeT'