Skip to content

Instantly share code, notes, and snippets.

@TerrorJack
Created September 9, 2018 06:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save TerrorJack/64386574b0aa8a56c99fd10d89cada53 to your computer and use it in GitHub Desktop.
Save TerrorJack/64386574b0aa8a56c99fd10d89cada53 to your computer and use it in GitHub Desktop.
Freer monad example
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -Wall #-}
module Freer
( Freer
, liftFreer
, foldFreer
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Free.Church
import Data.Functor.Coyoneda
newtype Freer f a =
Freer (forall m. MonadFree (Coyoneda f) m =>
m a)
instance Functor (Freer f) where
{-# INLINE fmap #-}
fmap = liftA
instance Applicative (Freer f) where
{-# INLINE pure #-}
pure a = Freer $ pure a
{-# INLINE (<*>) #-}
(<*>) = ap
instance Monad (Freer f) where
{-# INLINE return #-}
return = pure
{-# INLINE (>>=) #-}
Freer m >>= f =
Freer $
m >>= \a ->
let Freer r = f a
in r
{-# INLINE liftFreer #-}
liftFreer :: f a -> Freer f a
liftFreer f = Freer $ liftF $ liftCoyoneda f
{-# INLINE foldFreer #-}
foldFreer :: Monad g => (forall x. f x -> g x) -> Freer f a -> g a
foldFreer f (Freer m) = foldF (lowerCoyoneda . hoistCoyoneda f) m
{-# LANGUAGE GADTs #-}
{-# OPTIONS_GHC -Wall #-}
module FreerState where
import qualified Control.Monad.Reader as MTL
import qualified Control.Monad.State.Strict as MTL
import Control.Monad.Trans
import Data.IORef
import Freer
data State s a where
Get :: State s s
Put :: s -> State s ()
type StateM s = Freer (State s)
get :: StateM s s
get = liftFreer Get
put :: s -> StateM s ()
put = liftFreer . Put
runStatePure :: StateM s a -> s -> (a, s)
runStatePure = MTL.runState . foldFreer f
where
f :: State s a -> MTL.State s a
f Get = MTL.get
f (Put s) = MTL.put s
runStateIO :: StateM s a -> IORef s -> IO a
runStateIO = MTL.runReaderT . foldFreer f
where
f :: State s a -> MTL.ReaderT (IORef s) IO a
f Get = MTL.ask >>= lift . readIORef
f (Put s) = MTL.ask >>= \ref -> lift (writeIORef ref s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment