Revolucent icon

Learning Monads & Monad Transformers

Revolucent | PRO | 08/30/19 07:35:30 PM UTC | 0 ⭐ | 891 👁️ | Never ⏰ | []
Haskell |

2.75 KB

|

None

|

0 👍

/

0 👎

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
 
{-
This is an exercise in learning Haskell. I wrote these mostly in a clean-room fashion
as a way to figure out how to do monads, monad transformers, a Reader monad (RT) and
a state monad (ST).
-}
 
module Main where
 
import Control.Applicative
import Control.Monad.Identity
import Control.Monad.IO.Class
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Trans
import Data.Monoid
 
newtype RT r m a = RT { runRT :: r -> m a }
 
instance Functor m => Functor (RT r m) where
    fmap f (RT a) = RT $ fmap f . a 
 
instance Applicative m => Applicative (RT r m) where
    pure = RT . const . pure 
    (RT f) <*> (RT a) = RT $ \r -> (f r) <*> (a r)
 
instance Monad m => Monad (RT r m) where
    return = pure
    (RT a) >>= f = RT $ \r -> do
        a' <- a r
        runRT (f a') r
 
instance MonadTrans (RT r) where
    lift = RT . const 
 
instance MonadIO m => MonadIO (RT r m) where
    liftIO = lift . liftIO
 
instance Monad m => MonadReader r (RT r m) where
    ask = RT return
    local t (RT a) = RT $ \r -> a (t r)
 
type R r = RT r Identity
 
runR :: R r a -> r -> a
runR a = runIdentity . runRT a
 
newtype ST s m a = ST { runST :: s -> m (a, s) }
 
evalST a = fst . runST a
execST a = snd . runST a
 
instance Functor m => Functor (ST s m) where
    fmap f (ST a) = ST $ fmap (\(a', s') -> (f a', s')) . a
 
instance Monad m => Applicative (ST s m) where
    pure a = ST $ pure . (a,) 
    (ST f) <*> (ST a) = ST $ \s -> do 
        ~(f', s') <- f s 
        ~(a', s'') <- a s'
        return $ (f' a', s'')
 
instance Monad m => Monad (ST s m) where
    return = pure
    (ST a) >>= f = ST $ \s -> do
        ~(a', s') <- (a s)
        runST (f a') s'
 
instance Monad m => MonadState s (ST s m) where
    get = ST $ \s -> return (s, s)
    put s = ST $ \_ -> return ((), s)
 
instance MonadTrans (ST s) where 
    lift a = ST $ \s -> a >>= return . (,s) 
 
instance MonadIO m => MonadIO (ST s m) where
    liftIO = lift . liftIO
 
type S s = ST s Identity
 
runS :: S s a -> s -> (a, s)
runS a = runIdentity . runST a
 
evalS a = fst . runS a
execS a = snd . runS a
 
type RS a = RT a (S a) a
 
runRS :: Int -> Int -> RS Int -> (Int, Int)
runRS r s a = runS (runRT a r) s
 
evalRS r s a = fst $ runRS r s a
execRS r s a = snd $ runRS r s a 
 
x :: Int -> RT Int (S Int) Int
x n = do
    r <- ask
    s <- lift $ do
        modify (+n)
        get
    return $ (n * n) + (r * s)
 
main = print $ runS (runRT (liftA2 (+) (x 2) (x 1)) 2) 1

Comments