We'll looks at two patterns of computations that produce "effects":

1. producing, or "writing," something in addition to "real" output; and

2. "reading" from "environment" variables separate from "real" arguments.

Though the programming examples we'll use are small, but they will put us in a favorable state of mind for things to come.

## Writer_

``````newtype Writer_ w a = Writer_ { runWriter_ :: (a, w) }
deriving (Show)``````

### Example: Function Calls with Logging

Let's have the computation `(2*) . (^2) . (2*) \$ 3` explain its work.

We'll start by defining types to represent chatty functions.

``````data ChattyFunc a b =
ChattyFunc { name :: String, call :: a -> b }

type Chatty b =
Writer_ [String] b

applyChattyFunc :: (Show a, Show b) => ChattyFunc a b -> a -> Chatty b
applyChattyFunc chattyFunc a =
let
b = call chattyFunc a
s = name chattyFunc ++ " " ++ show a ++ " = " ++ show b
in
Writer_ (b, [s])

printLog :: Chatty a -> IO ()
printLog = putStrLn . unlines . snd . runWriter_``````

Now we can construct and apply chatty functions.

``````square = ChattyFunc "square" (^2)
double = ChattyFunc "double" (2*)

doubleSquareDouble :: Int -> Chatty Int
doubleSquareDouble n0 =
let
Writer_ (n1, w1) = applyChattyFunc double n0
Writer_ (n2, w2) = applyChattyFunc double n1
Writer_ (n3, w3) = applyChattyFunc double n2
in
Writer_ (n3, w1 <> w2 <> w3)``````

Chat log:

``````> doubleSquareDouble 3
Writer_ (72,["Calling doubleSquareDouble","double 3 = 6","square 6 = 36","double 36 = 72"])

> printLog \$ doubleSquareDouble 3
Calling doubleSquareDouble
double 3 = 6
square 6 = 36
double 36 = 72``````

``````instance Monoid w => Monad (Writer_ w) where
-- return :: a -> Writer_ a w
return a = Writer_ (a, mempty)

-- (>>=) :: Writer_ a w -> (a -> Writer_ w b) -> Writer_ w b
Writer_ (a, w1) >>= f =
let Writer_ (b, w2) = f a in
Writer_ (b, w1 <> w2)``````
``````instance Monoid w => Applicative (Writer_ w) where
pure  = return
(<*>) = ap

instance Monoid w => Functor (Writer_ w) where
fmap f x = pure f <*> x``````

### Helper Functions

``````tell :: w -> Writer_ w ()
tell w = Writer_ ((), w)

censor :: (w -> w) -> Writer_ w a -> Writer_ w a
censor f (Writer_ (a, w)) = Writer_ \$ (a, f w)
censor f                  = Writer_ . fmap f . runWriter_``````

### More Chatting

``````doubleSquareDouble :: Int -> Chatty Int
doubleSquareDouble n0 = do
tell ["Calling doubleSquareDouble"]
n1 <- applyChattyFunc double n0
n2 <- applyChattyFunc square n1
n3 <- applyChattyFunc double n2
pure n3``````

``````> printLog \$ doubleSquareDouble 3
Calling doubleSquareDouble
double 3 = 6
square 6 = 36
double 36 = 72

> printLog \$ censor (const []) \$ doubleSquareDouble 3

> printLog \$ censor (map (const "BLEEP")) \$ doubleSquareDouble 3
BLEEP
BLEEP
BLEEP
BLEEP

> printLog \$ censor (map (map (const '*'))) \$ doubleSquareDouble 3
**************************
************
*************
**************``````

We've seen `Functor` and `Applicative` instances for `((->) t)`. There's a `Monad` instance too. This type is often called the "reader" — or "environment" — monad. We'll use the type variable `env` below to remind us of this name.

``````instance Monad ((->) env) where
-- (>>=) :: (env -> a) -> (a -> env -> b) -> (env -> b)
f >>= g = \env -> g (f env) env``````

The key is the type of "actions" `(a -> env -> b)` that are going to get stitched together. They're binary functions, where the second argument is an "environment." More precisely, it is the environment — the functions `f` and `g` do not produce new values of type `env`, so the environment "does not change."

It's hard to demonstrate the utility with a very small example. But as programs grow larger and many functions take the same set of environment (or configuration) parameters, the reader monad can make passing around these parameters implicit. The following contrived example...

``````applyWithMax f n max
| f n > max = Nothing
| otherwise = Just \$ f n

squareWithMax = applyWithMax (^2)

foo :: (Int,Int,Int) -> Int -> Maybe Int
foo (n1,n2,n3) max =
squareWithMax n1 max
<|> squareWithMax n2 max
<|> squareWithMax n3 max``````

suffices to demonstrate how the environment can be "hidden"...

``````foo' :: (Int,Int,Int) -> Int -> Maybe Int
foo' (n1,n2,n3) = do
mn1 <- squareWithMax n1
mn2 <- squareWithMax n2
mn3 <- squareWithMax n3
pure \$ mn1 <|> mn2 <|> mn3``````

``````> foo' (10, 5, 3) 50
Just 25
> foo' (10, 5, 3) 50
Just 25``````

Note that this example actually depends only on the `Applicative` interface of `((->) env)`, not `Monad`.

``````foo'' :: (Int,Int,Int) -> Int -> Maybe Int
foo'' (n1,n2,n3) =
pure (\mn1 mn2 mn3 -> mn1 <|> mn2 <|> mn3)
<*> squareWithMax n1
<*> squareWithMax n2
<*> squareWithMax n3``````

We'll have more to say about `Applicative` and `Monad` later.

## From `Writer_` and `Reader_` to `Writer` and `Reader`

These will pop out of the library in due course, as a result of rather more exotic features...