diff --git a/Control/Monad/BrainFuck.hs b/Control/Monad/BrainFuck.hs
--- a/Control/Monad/BrainFuck.hs
+++ b/Control/Monad/BrainFuck.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE EmptyDataDecls #-}
-
 module Control.Monad.BrainFuck where
 
 import qualified Control.Monad as M
+import qualified Data.Char as Char
 
 newtype BrainFuck a = BrainFuck (DataPointer -> ([Char], DataPointer, a))
 
@@ -25,21 +24,21 @@
 
 next, prev, incr, decr, output, input, open, close :: BrainFuck ()
 -- | move data pointer right
-next = cmd' succ '>'
+next = opcode' succ '>'
 -- | move data pointer left
-prev = cmd' pred '<'
+prev = opcode' pred '<'
 -- | increment data
-incr = cmd '+'
+incr = opcode '+'
 -- | decrement data
-decr = cmd '-'
+decr = opcode '-'
 -- | output byte at data pointer
-output = cmd '.'
+output = opcode '.'
 -- | input byte, storing at data pointer
-input = cmd ','
+input = opcode ','
 -- | if byte at data pointer is zero, jump to command after close
-open = cmd '['
+open = opcode '['
 -- | if byte at data pointer is nonzero, jump to command after matching open
-close = cmd ']'
+close = opcode ']'
 
 add, sub :: Int -> BrainFuck ()
 add = multi incr
@@ -47,14 +46,14 @@
 
 -- | Adds an arbitrary character to the program.
 -- Should not be used directly.
-cmd :: Char -> BrainFuck ()
-cmd = cmd' id
+opcode :: Char -> BrainFuck ()
+opcode = opcode' id
 
 -- | Adds an arbitrary character to the program,
 -- and updates the data pointer.
 -- Should not be used directly.
-cmd' :: (DataPointer -> DataPointer) -> Char -> BrainFuck ()
-cmd' f x =  BrainFuck $ \loc -> ([x], f loc, ())
+opcode' :: (DataPointer -> DataPointer) -> Char -> BrainFuck ()
+opcode' f x =  BrainFuck $ \loc -> ([x], f loc, ())
 
 -- | Run an action multiple times.
 multi :: BrainFuck () -> Int -> BrainFuck ()
@@ -62,6 +61,23 @@
 	_ <- sequence (replicate n c)
 	return ()
 
+-- | Assuming that the data pointer points to a 0, changes
+-- it to the value of a Char.
+char :: Char.Char -> BrainFuck ()
+char = multi incr . Char.ord
+
+-- | Undoes `char`
+unchar :: Char.Char -> BrainFuck ()
+unchar = multi decr . Char.ord
+
+-- | Runs an action with the data pointer pointing at a Char.
+withChar :: Char.Char -> BrainFuck a -> BrainFuck a
+withChar c a = do
+	char c
+	r <- a
+	unchar c
+	return r
+
 -- | Gets the current address of the data pointer.
 addr :: BrainFuck DataPointer
 addr = BrainFuck $ \loc -> ([], loc, loc)
@@ -76,38 +92,40 @@
 			then next >> setAddr n
 			else return ()
 
--- | The loop is only entered if the byte at the data pointer is not zero.
+-- | The loop is only run if the data pointer doesn't point to 0.
 --
--- On entry, the loop body is run, and then it loops when
--- the byte at the data pointer is not zero.
+-- On entry, the loop body is run, and then it loops, until the data
+-- pointer points to 0.
 loopUnless0 :: BrainFuck () -> BrainFuck ()
 loopUnless0 a = do
 	open
 	a
 	close
 
-data Constants
+data Constants = Constants NumConstants Integer
 
--- | Let's run programs with data cells 0-8 reserved to always contain
--- the numbers 0 to 8.
+type NumConstants = Int
+
+-- | Let's run programs with data addresses 0..n reserved to always contain
+-- the numbers n..0
 --
 -- These constants will make brainfuck quite a bit easier to use!
-brainfuckConstants :: (Constants -> BrainFuck a) -> String
-brainfuckConstants a = brainfuck $ do
-	M.forM_ [0..8] $ \n -> do
-		add n
+brainfuckConstants :: NumConstants -> (Constants -> BrainFuck a) -> String
+brainfuckConstants numconstants a = brainfuck $ do
+	M.forM_ [0..numconstants] $ \n -> do
+		add (numconstants - n)
 		next
-	a (undefined :: Constants)
+	a (Constants numconstants 0)
 
 -- | Sets data pointer to point to one of the Constants.
-at :: Constants -> Integer -> BrainFuck ()
-at _ = setAddr
+pointAt :: Constants -> Integer -> BrainFuck ()
+pointAt (Constants numconstants c) i = setAddr (c + fromIntegral numconstants - i)
 
--- | Run an action in a loop, until it sets its data pointer to 0.
+-- | Run an action in a loop, until the data pointer points to 0.
 loop :: Constants -> BrainFuck () -> BrainFuck ()
 loop constants a = do
 	here <- addr
-	at constants 1
+	pointAt constants 1
 	loopUnless0 $ do
 		setAddr here
 		a
@@ -116,14 +134,22 @@
 forever :: Constants -> BrainFuck () -> BrainFuck ()
 forever constants a = loop constants $ do
 	a
-	at constants 1
+	pointAt constants 1
 
--- | Prints out the ASCII table, starting with space, repeatedly.
+-- | Prints out the ASCII characters, starting with space, repeatedly.
 -- 
 -- TODO: Only print printable characters.
 demo :: String
-demo = brainfuckConstants $ \constants -> do
-	add 32
+demo = brainfuckConstants 1 $ \constants -> do
+	add $ Char.ord ' '
 	forever constants $ do
 		add 1
 		output
+
+cat :: String
+cat = brainfuckConstants 1 $ flip forever $ input >> output
+
+helloworld :: String
+helloworld = brainfuck $
+	M.forM_ "hello, world!" $
+		flip withChar output
diff --git a/brainfuck-monad.cabal b/brainfuck-monad.cabal
--- a/brainfuck-monad.cabal
+++ b/brainfuck-monad.cabal
@@ -1,5 +1,5 @@
 Name: brainfuck-monad
-Version: 0.0.1
+Version: 0.1.0
 Cabal-Version: >= 1.8
 License: BSD3
 Maintainer: Joey Hess <id@joeyh.name>
@@ -8,7 +8,7 @@
 Copyright: 2014 Joey Hess
 License-File: LICENSE
 Build-Type: Simple
-Category: Utility
+Category: Compilers/Interpreters
 Synopsis: BrainFuck monad
 Description:
  This is a BrainFuck monad, for generating brainfuck programs.
