packages feed

functor-monad-0.1.1.0: examples/ListTVia.hs

{-# LANGUAGE
  StandaloneKindSignatures,
  DerivingVia,
  DerivingStrategies,
  DeriveFunctor,
  StandaloneDeriving,
  RankNTypes,
  ScopedTypeVariables,
  InstanceSigs,
  TypeOperators,
  TupleSections,
  QuantifiedConstraints
#-}
module Main(main) where

import Data.Kind ( Type )

import Data.Monoid (Ap(..))
import Control.Monad.Trans.Class
import Control.Monad.Trans.Free
import FMonad.FreeT
import Control.Monad.Trail

{-

This example is inspired by a question raised at r/haskell (in fact, it inspired me to make
this package itself!)

ListT instances and -XDerivingVia: https://www.reddit.com/r/haskell/comments/i76yx2/listt_instances_and_xderivingvia/

> how can we derive @Monad@, @Alternative@, @Monoid@.. instances for @ListT@? 

-}

type    ListT :: (Type -> Type) -> (Type -> Type)
newtype ListT m a = ListT { runListT :: FreeT ((,) a) m () }
    deriving stock (Eq, Ord, Show, Read)
    deriving (Functor, Applicative, Monad)
        via (Trail (FreeT' m))
    deriving (Semigroup, Monoid)
        via (Ap (FreeT ((,) a) m) ())

-- MonadTrans is specific to ListT
instance MonadTrans ListT where
  lift ma = ListT $ lift ma >>= \a -> liftF (a, ())

-- For test:
forEach :: Monad m => ListT m a -> (a -> m ()) -> m ()
forEach as f = iterT (\(a, m) -> f a >> m) . runListT $ as

test1, test2, test3 :: ListT IO Int
test1 = lift (putStrLn "SideEffect: A") >> mempty
test2 = lift (putStrLn "SideEffect: B") >> pure 1
test3 = lift (putStrLn "SideEffect: C") >> (pure 2 <> pure 3)

main :: IO ()
main = forEach test print
  where test = (test1 <> test2 <> test3) >>= \n -> pure 100 <> pure n