If you feed that into a brainfuck interpreter (I'm using hsbrainfuck for my
testing), you'll find that it loops forever and prints out each character,
starting with space (32), in ASCIIbetical order.

The implementation is quite similar to the ASM monad. The main differences
are that it builds a String, and that the BrainFuck monad keeps track
of the current position of the data pointer (as brainfuck lacks any
sane way to manipulate its instruction pointer).

Of course, brainfuck is a horrible language, designed to be nearly impossible
to use. Here's the code to run a loop, but it's really hard to use this to
build anything useful..

-- The loop is only entered if the byte at the data pointer is not zero.-- On entry, the loop body is run, and then it loops when-- the byte at the data pointer is not zero.
loopUnless0 :: BrainFuck () -> BrainFuck ()
loopUnless0 a =do
open
a
close

To tame brainfuck a bit, I decided to treat data addresses 0-8 as constants,
which will contain the numbers 0-8. Otherwise, it's very hard to ensure
that the data pointer is pointing at a nonzero number when you want
to start a loop. (After all, brainfuck doesn't let you set data
to some fixed value like 0 or 1!)

I wrote a little brainfuckConstants that runs a BrainFuck
program with these constants set up at the beginning.
It just generates the brainfuck code for a series of ASCII art fishes:
>+>++>+++>++++>+++++>++++++>+++++++>++++++++>

With the fishes^Wconstants in place, it's possible to write a more useful
loop. Notice how the data pointer location is saved at the beginning, and
restored inside the loop body. This ensures that the provided BrainFuck
action doesn't stomp on our constants.

I haven't bothered to make sure that the constants are really constant,
but that could be done. It would just need a Control.Monad.BrainFuck.Safe
module, that uses a different monad, in which incr and decr and input
don't do anything when the data pointer is pointing at a constant.
Or, perhaps this could be statically checked at the type level, with
type level naturals. It's Haskell, we can make it safer if we want to. ;)

So, not only does this BrainFuck monad allow writing brainfuck code using
crazy haskell syntax, instead of crazy brainfuck syntax, but it
allows doing some higher-level programming, building up a useful(!?) library
of BrainFuck combinators and using them to generate brainfuck code
you'd not want to try to write by hand.

Of course, the real point is that "monad" and "brainfuck" so obviously
belonged together that it would have been a crime not to write this.

Instead of the constants hack, it's useful to define a stack-based
function call model in brainfuck. This alloc higher-level function
implements that, and is simplifying the code significantly.

-- | For higher-level programming in brainfuck, it's useful to have a way
-- to run a function, while allocating a memory cell, which is initialized
-- to contain 0.
--
-- This and many of the functions below assume that
-- cells to the left are in use, while cells to the right
-- are unused and may contain any data. Higher-level functions should
-- generally avoid changing the current cell, and should instead alloc
-- a new one to use.
alloc :: BrainFuck a -> BrainFuck a
alloc a = do
next
zero
cell <- addr
r <- a
setAddr cell
prev
return r

Using alloc, we can build a nicer loopFrom, etc.

-- | Allocates a cell and uses it as the loop counter, starting from
-- the provided value. The action will continue running in a loop until
-- it decrements the counter to 0.
loopFrom :: Int -> (DataPointer -> BrainFuck ()) -> BrainFuck ()
loopFrom n a = alloc $ do
i <- addr
add n
loopUnless0 $ do
a i
setAddr i