Posted on May 24, 2015
by Stuart Popejoy.
Literate
source

To code any decent-sized application in Haskell, you have to be comfortable with *effectful* programming.

Haskell famously offers “pure” functions, and they are great, referentially transparent and all that. But IO will be done. Assuming you want to factor your IO activity into more than just `main`

, your app will have a lot of functions in IO (or `MonadIO`

).

At the same time, you’ll want to enrich your pure functions with core library modules that “encode” effectful behavior into your types, like maintaining state, or reading from a static environment. Finally, you’ll want to integrate all of this with fancy solutions like webservers, http clients, loggers, database access, and such.

This article is the first in a series on “effectful programming”. My informal definition of “effectful” encompasses

- Actual side-effects (IO)
- Stuff that seems like side-effects (State, Writer, etc.)
- Contexts that persist over function calls (Reader, State, etc.)
- Non-local control flow (Maybe, Either).

In all of these cases, “pure” programming, mapping specified inputs to outputs, gives way to richer metaphors that offer all the utility of imperative or mutable programming, but with the *exact contract of execution* specified in the type.

It’s the best of all possible worlds. Let’s get started.

```
import Data.Set (Set,singleton)
import Control.Applicative ((<$>))
```

To write an app, you implement `main :: IO ()`

.

```
main :: IO ()
main = putStrLn "Hello World!"
```

`main`

is the gateway drug into `IO`

, and the first one’s free. “Hello World” is a one-liner, requiring no imports, and not even a type signature if you’re really lazy.

Functions with the famous type signature `IO ()`

have zero functional mojo; we run them for side-effects only. You can use `IO ()`

to squander any benefits of strongly-typed functional programming, with magical values emerging from the big scary world outside the compiler.

```
sendSecret :: IO ()
sendSecret = writeFile "/tmp/secret" "Who is Benjamin Disraeli?"
```

```
andTheAnswerIs :: IO String
andTheAnswerIs = readFile "/tmp/secret"
```

Fortunately, IO isn’t an all-or-nothing proposition.

First and most obviously, you can use pure code in IO whenever you like. This will arise naturally if your factoring is halfway decent.

```
-- | pure function to count characters in a string
countChar :: Char -> String -> Int
countChar c = length . filter (==c)
```

```
-- | use 'countChar' in IO on a file
countCharInFile :: Char -> FilePath -> IO Int
countCharInFile c f = do
contents <- readFile f
return (countChar c contents)
```

`countChar`

is 100% pure, and easy to test in GHCI.

```
ghci> countChar 'a' "aba"
2
```

However, GHCI makes it easy to test IO functions too. Let’s see how many times ‘a’ shows up in this article:

```
ghci> countCharInFile 'a' "posts/Effectful01.lhs"
1106
```

So what is this strange thing we call `IO`

?

IO in haskell is famously a Monad, but first and foremost, it’s just another *type*. Its kind is `* -> *`

. ^{1}

```
ghci> :k IO
IO :: * -> *
```

Thus, just like you’d write `Set String`

to make Set inhabitable with String values, you write `IO Handle`

to indicate an IO action that produces a Handle.

If you want an `IO`

action that produces a Set of Strings, you’ll need to break out parentheses:

```
setProducingAction :: IO (Set String)
setProducingAction = return $ singleton "contrived"
```

As we noted above, `IO ()`

means the function has no meaningful output. `()`

is the “unit type”, with the single inhabitant `()`

. It allows us to return a value from a function (and thus still be “functional”, as opposed to `void`

functions in other languages), but indicate that the return value is of no meaning.

`IO ()`

indicates we only execute this action for its side effects. However, functions like `readFile`

are of type `IO String`

, meaning “run side-effects and give me a `String`

result.”

In this regard, the two-kinded–ness of `IO`

means something completely different than, say, `Set`

. The second type in Set indicates what values it “holds”; the second type in IO indicates what single value it “produces”.

IO is obviously an action-packed, effect-having champ. However, it is also “effectful” in a larger sense, since IO implements the typeclasses `Functor`

, `Applicative`

and `Monad`

. These form a hierarchy, such that any `Monad`

is an `Applicative`

, and any `Applicative`

is a `Functor`

. ^{2}.

These are the “effectful trio” of abstractions: all of the types we’ll use to level-up our code implement them. Effectful programming in Haskell is all about learning how to leverage the APIs of these types. Let’s start with the most powerful, `Monad`

.

Anything that is a `Monad`

will support certain operations. Let’s ask GHCI what they are:

```
ghci> :i Monad
class Monad (m :: * -> *) where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
```

We see four functions making up the typeclass. We also see that any Monad must be of kind `* -> *`

, like IO. This is true of `Applicative`

and `Functor`

as well.

The two most important functions in Monad are `return`

and `(>>=)`

; the second is an infix operator called “bind”. Let’s look at each.

In isolation, `return`

is disarmingly straightforward, albeit with a strange name.

```
ghci> :t return
return :: Monad m => a -> m a
```

It simply allows you to stick a value into the monadic “context”. Take an `a`

, you get `Monad m => m a`

.

```
returnIsEasy :: String -> IO String
returnIsEasy s = return (s ++ " is in IOooooooo")
```

Just like that, we wrapped a String in `IO`

. We’re coding with the pros.

Note that `return`

is unnecessary if you’re calling a function that is already in your monad:

```
ioNoReturn :: IO String
ioNoReturn = returnIsEasy "Elvis"
```

Pretty minimal. What’s the point? The clue is in the name `return`

.

Functions whose type is monadic (their result is of type `Monad x`

) are different than your usual function: instead of returning the monad, they “run inside” the monadic context, and any values must be “returned” back to the context.

So to really understand `return`

, we have to understand its partner in crime, bind.

Bind is the real magic of `Monad`

, formalizing how you operate on a monadic value.

In monadic operation, we don’t simply grab the underlying value and go to town. Instead, we use “bind” to get at the good stuff: you have to supply a *function* to operate on the value and “give it back” to the monadic context. The type makes this clear:

```
ghci> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
```

The first argument to `>>=`

is the monad itself, `m a`

. The second argument is the monadic function, which takes the bare value `a`

and gets to work, producing the transformed value `b`

in the monadic context: `(a -> m b)`

.

This inversion of control allows the Monad instance to enforce all kinds of invariants on what that computation is allowed to do. You don’t simply “call” a monadic function, you “bind” to it. You don’t simply return a value from a function, you “return” it back to the context, using the API provided by the monad. The monad’s code is in charge.

It’s a mode of computation of staggering generality and utility. Monadic functions working under `bind`

have a different “shape” than normal input-to-output functions. This makes radically different modes of computation available to pure code.

Indeed, `IO`

is a funny instance in the effectful zoo. When we use types like `State`

and `Reader`

and `Maybe`

we reap huge gains in elegance and power; what’s more, the code is right there on Hackage for us to study and understand.

IO, however, is mysterious. Its guts are buried deep inside GHC. We use it as a monad “just because” – a program without IO isn’t much of a program.

Instead, it’s the *compiler* getting the main utility from monadic control. Through `Monad`

, the compiler can ensure that all our `IO`

commands happen in strict sequence, helping it safely move values in and out of the pure runtime.

The good news is that Monad (with its effectful cousins) is a fantastic abstraction for `IO`

, making it easy to compose and factor other effectful types with it.

Working with bind isn’t hard once you get used to it.

The bind operator, `>>=`

, is used infix, with a monad inhabitant on the left side, and our consuming function on the right. This creates a left-to-right code “motion”:

```
countCharInFileBind :: Char -> FilePath -> IO Int
countCharInFileBind c f =
readFile f >>= \cs -> return (countChar c cs)
```

Our function counts how often a character shows up in a text file. We bind “`readFile f`

”, of type `IO String`

, with a lambda function. Its argument `cs`

has the contents of the file from `readFile`

. In the lambda, we call our pure function `countChar`

, and `return`

the Int result back to IO.

With eta reduction, bind makes for some beautiful compositions:

```
countCharInFileEta :: Char -> FilePath -> IO Int
countCharInFileEta c f = readFile f >>= return . countChar c
```

The infix syntax really shines here, with the `cs`

argument composing onto the end of `countChar c`

. It’s as though `>>=`

were a “pipeline,” flowing the contents of the file into our composition `return . countChar c`

.

When we use functions of type `IO ()`

, we’re only interested in the side effects. Nonetheless, we still have to bind to use them, leaving us with an unused argument of type `()`

.

An example is `putStrLn`

, which writes a line of text to stdout. Let’s use it to log a message before performing our computation:

```
countCharMsgBind :: Char -> FilePath -> IO Int
countCharMsgBind c f =
putStrLn ("count " ++ [c] ++ " in " ++ f)
>>= \_ -> readFile f -- yuck
>>= return . countChar c
```

The “`\_ ->`

” is pointless. Enter `>>`

, a modified bind that swallows the useless argument.

```
ghci> :t (>>)
(>>) :: Monad m => m a -> m b -> m b
```

With `>>`

, we simply “sequence” the next action.

```
countCharMsg :: Char -> FilePath -> IO Int
countCharMsg c f =
putStrLn ("count " ++ [c] ++ " in " ++ f)
>> readFile f -- much better!
>>= return . countChar c
```

`where`

and `let ... in`

can be interchanged in pure code as a matter of style. In monadic code however, it gets tricky to use `where`

.

Let’s change our logging to output the character count. To do so we’ll need to capture it in a variable first, so we fire up a `where`

clause. Unfortunately, the compiler yells at us.

```
countCharBroken c f =
readFile f >>=
\cs -> putStrLn ("Counted " ++ show count ++ " chars")
>> return count
where count = countChar c cs
posts/Effectful.lhs:332:32-33: Not in scope: ‘cs’ …
Compilation failed.
```

As the error shows, the lambda after `readFile f`

is not in scope for the `where`

section. Only `c`

and `f`

from the top level are in scope. There’s not really any good place to put the `where`

.

`let`

and `in`

work better, “above” the lambdas that need it.

```
countCharLog :: Char -> FilePath -> IO Int
countCharLog c f =
readFile f >>=
\cs -> let count = countChar c cs
in putStrLn ("Counted " ++ show count ++ " chars")
>> return count
```

If you’ve got a lot of work to do, writing a ton of lambdas can get unwieldy and confusing. Our simple function `countCharLog`

has three lambdas; we can easily imagine more.

Enter `do`

notation, an alternate syntax for Monads which nicely “cleans up” repeated `>>=`

, `>>`

and `let`

expressions. Here’s `countCharLog`

rewritten with `do`

:

```
countCharLogDo :: Char -> FilePath -> IO Int
countCharLogDo c f = do
cs <- readFile f
let count = countChar c cs
putStrLn $ "Counted " ++ show count ++ " chars"
return count
```

Starting from the top, we have “`cs <- readFile f`

”. “`<-`

” is the “draw from” operator, which invokes bind under the hood. The argument of the next lambda appears as an “assignment” on the left of the arrow. The following expressions have `cs`

in scope, exactly like nested lambdas.

Next we define `count`

with `let`

. No `in`

is required: definitions are automatically in scope for subsequent expressions.

Our side-effect–only expression comes next. We simply issue our `putStrLn`

call and proceed to the next line. Under the hood, this is sequenced to the following expression with `>>`

.

If you stare long enough at `countCharLog`

and `countCharLogDo`

, you’ll see how `do`

notation is simply a reformat of our bind lambdas, leveraging newlines to clean up the code.

Do notation has been characterized as a way to “write imperative code in Haskell”, ostensibly “easier to read” than, say, the right-to-left sequencing of function composition. This perhaps explains some of the general confusion surrounding Monads, when they are seen as “programmable semicolons” or some other broken metaphor about imperative coding.

It is far better to see `do`

as simply a code-cleaning tool. It’s a way of chaining binds of monadic functions and lambdas, with the left-to-right, top-to-bottom orientation accumulating variables in scope. It’s a *style*, embedded in syntax.

Monads don’t have to go left-to-right. “Reverse bind” (`=<<`

) can be used to write monadic code that flows the other way.

```
countCharRevBind :: Char -> FilePath -> IO Int
countCharRevBind c f = return . countChar c =<< readFile f
```

This looks more like functional code. However some syntactic gotchas await.

In a pure function, `f`

would be a candidate for eta reduction. Unfortunately, the infix precedences of `=<<`

and `.`

don’t play nicely, so point-free style gets a little clumsy.

```
countCharRevEta :: Char -> FilePath -> IO Int
countCharRevEta c = (return . countChar c =<<) . readFile
```

“Forward” bind works better with the other infix operators, and maps directly to `do`

sugar. Thus, it’s easier and more idiomatic to use `>>=`

(and `do`

) instead of reverse bind.

Like all sugar, `do`

notation gets addictive. Until you’re really comfortable with monads, you should regularly “de-sugar” `do`

blocks back into `>>=`

, `>>`

, `let`

and lambdas. This will reveal the monadic functionality explicitly.

Since `IO`

is a Monad, it’s also a `Functor`

, which is horribly useful.

`Functor`

’s main function is `fmap`

. It looks a lot like Monad’s reverse bind.

```
ghci> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
ghci> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
```

Unlike bind, the function used in `fmap`

is “pure”: it makes the transformation from `a`

to `b`

without needing to `return`

it to the context. The Functor implementation itself will lift the `b`

result for us “outside” the function.

`fmap`

is really the classic functional operation `map`

, best known as a way to transform all of the elements in a list.

```
incrementAllBy :: Int -> [Int] -> [Int]
incrementAllBy i is = fmap (+ i) is
```

```
ghci> incrementAllBy 2 [1,2,3]
[3,4,5]
```

Many tourists to functional programming learn `map`

(and maybe its cousin `reduce`

/`fold`

) as a list operation only, before proudly stamping FP onto their resume. Haskellers go a lot further with `Functor`

, mapping functions over *any* type with the `Functor`

shape.

With the effectful types, `fmap`

allows us to “plug” a pure operation into an effectful one.

Bind forces us to shape effectful operations differently than pure ones. It can therefore be tempting to see pure transformations as in “a different world”, confining them to `let`

clauses or stashing them in other functions altogether. The effectful programmer instead uses `fmap`

on monadic values, composing pure transformations with an effectful result.

Our char-counting function is an excellent candidate for plugging in `fmap`

.

```
countCharFmap :: Char -> FilePath -> IO Int
countCharFmap c f = fmap (countChar c) (readFile f)
```

Our code is looking more and more functional – the only indication here that our function is at all impure is the type `IO Int`

. Let’s “follow the types” to see how `fmap`

accomplishes this:

```
ghci> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
ghci> :t countChar 'c'
countChar 'c' :: String -> Int
ghci> :t readFile "path"
readFile "path" :: IO String
```

Here, we’re using GHCI to examine the types of partially- and fully-applied functions. `countChar 'c'`

creates a unary function of type `String -> Int`

, which is suitable for “plugging into” `fmap`

. Meanwhile, the fully-applied `readFile "path"`

is of type `IO String`

– and IO is a `Functor`

.

Putting the types together, we see the resulting type is `IO Int`

.

```
ghci> :t fmap (countChar 'c') (readFile "path")
fmap (countChar 'c') (readFile "path") :: IO Int
```

In short, we use `fmap`

to convert our effectful `String`

result into an `Int`

. The pure conversion happens *within the effectful context:* no `return`

required.

`fmap`

has an infix synonym `<$>`

, which we can use to make those pesky parentheses disappear.

```
countCharInfix :: Char -> FilePath -> IO Int
countCharInfix c f = countChar c <$> readFile f
```

That’s some pretty sweet code right there.

So far we’ve focused our Monad/Functor discussion on `IO`

while referencing other “effectful” types. It’s important to realize that nothing about Monad or Functor is necessarily effect-related. To do this, let’s take a quick glance at the humble list type, `[a]`

.

We know already that it’s a `Functor`

: the `map`

operation is a “Greatest Hit” of functional programming. Intuitively, we can imagine applying a function to every element of a list, creating a new list with the transformed elements. How is it a `Monad`

though?

`return`

is easy. It simply creates a singleton list out of the value.

```
ghci> return 1 :: [Int]
[1]
```

Bind is more interesting. It’s type is “`[a] -> (a -> [b]) -> [b]`

”: the monadic function will take each value of the list, and return the transformed result *as a list*.

The result is a new list, but made from a bunch of *list results*, not individual values like `fmap`

. Therefore the List monad must *concatenate* these results to make the new list.

We can see therefore how `Monad`

offers strictly more powerful transformations than `Functor`

. `fmap`

can only transform an individual value “in place”, while `>>=`

can return an empty list, or a list with more elements than the original. Functor is “structure preserving”, while Monad is “structure transforming”.

Here’s a simple example, using bind to repeat `Int`

values as many times as the value itself.

```
listBindEx :: [Int] -> [Int]
listBindEx is = is >>= (\i -> replicate i i)
```

```
ghci> listBindEx [1,2,3]
[1,2,2,3,3,3]
```

The intermediate values `[1]`

, `[2,2]`

and `[3,3,3]`

have been merged to create the final results.

To make things more interesting, let’s look at what it means to bind up two lists. We’ll use `do`

notation to avoid unsightly bind lambdas.

```
listBindTwo :: [Int] -> [Int] -> [Int]
listBindTwo is js = do
i <- is
j <- js
[i,j]
```

```
ghci> listBindTwo [1,2,3] [5,6]
[1,5,1,6,2,5,2,6,3,5,3,6]
```

It looks a lot like “list comprehensions”, which is no accident. List comprehensions are indeed the Monadic use case for lists. Lists are therefore first-class Monads, which is a great way to unseat the assumption that Monads are somehow “imperative”.

In `listBindTwo`

, it is impossible to interpret `i <- is`

happening “before” `j <- js`

. They are simply two nested lambdas that produce the cartesian result of the two lists. How we *declare* functions is not necessarily related to how they *fire*.

We’ve covered a lot of ground, but we’re just getting started.

The next article will turn to the pure effectful types, and introduce `Applicative`

use cases. We’ll look at monad transformers, plus the typeclasses surrounding them that make working with transformers so much easier.

Finally we’ll sew them all together in a fully-working, if trivial, example. Stay tuned!

See this article for an intro to kinds.↩

The Functor-Applicative-Monad hierarchy was only a convention until recently, when GHC 7.10 started enforcing it.↩