diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,12 @@
+brainfuck-monad (0.5.0) unstable; urgency=medium
+
+  * Applicative instance.
+  * Can use movfuscator to build elf executables.
+
+ -- Joey Hess <id@joeyh.name>  Fri, 25 Sep 2015 16:01:03 -0400
+
+brainfuck-monad (0.4.0) unstable; urgency=low
+
+  * First release.
+
+ -- Joey Hess <joeyh@debian.org>  Wed, 02 Apr 2014 13:57:42 -0400
diff --git a/Control/Monad/BrainFuck.hs b/Control/Monad/BrainFuck.hs
--- a/Control/Monad/BrainFuck.hs
+++ b/Control/Monad/BrainFuck.hs
@@ -1,10 +1,19 @@
+{-# LANGUAGE DeriveFunctor #-}
+
 module Control.Monad.BrainFuck where
 
 import qualified Control.Monad as M
+import Control.Applicative
+import Control.Monad (ap)
 import qualified Data.Char as Char
 import Data.Word (Word8)
+import System.Process
+import System.IO
+import System.Exit
+import System.Directory
 
 newtype BrainFuck a = BrainFuck (DataPointer -> ([Char], DataPointer, a))
+	deriving (Functor)
 
 type DataPointer = Integer
 
@@ -17,13 +26,17 @@
 brainfuck (BrainFuck f) = bytes where (bytes, _, _) = f 0
 
 instance Monad BrainFuck where
-	return ret = BrainFuck $ \loc -> ([], loc, ret)
+	return = pure
 	a >>= b = BrainFuck $ \start -> let
 		(left, mid, val) = func a start
 		(right, end, ret) = func (b val) mid
 		in (left ++ right, end, ret)
 
-next, prev, incr, decr, output, input, open, close :: BrainFuck ()
+instance Applicative BrainFuck where
+	pure v = BrainFuck $ \loc -> ([], loc, v)
+	(<*>) = ap
+
+next, prev, incr, decr, output, input, open, close, debug :: BrainFuck ()
 -- | move data pointer right
 next = opcode' succ '>'
 -- | move data pointer left
@@ -163,9 +176,9 @@
 -- current memory cell, or allocate and use new ones, and will not
 -- exit the loop.
 forever :: BrainFuck a -> BrainFuck ()
-forever a = loopFrom 1 $ \i ->
-	alloc' $ \scratch -> do
-		a
+forever a = loopFrom 1 $ \_i ->
+	alloc' $ \_scratch -> do
+		_ <- a
 		return ()
 
 -- | Copies the value of a cell.
@@ -255,7 +268,7 @@
 		setAddr c1
 		loopUnless0 $ do
 			decr
-			loopFrom y $ \c2 -> do
+			loopFrom y $ \_c2 -> do
 				decr
 				setAddr x
 				incr
@@ -269,7 +282,7 @@
 	-- Get to letter 104 ('a' is 97) quickly by multiplication.
 	start = do
 		zero
-		x <- addr
+		_x <- addr
 		add 13
 		mult 8
 		return (13 * 8)
@@ -289,7 +302,10 @@
 -- | Prints out the alphabet, repeatedly, with some whitespace fun
 -- to make it more interesting.
 demo :: String
-demo = brainfuck $ alloc' $ \tilt -> do
+demo = brainfuck demo'
+
+demo' :: BrainFuck () 
+demo' = alloc' $ \tilt -> do
 	settilt
 	alloc' $ \tc -> do
 		decr -- set to 255
@@ -297,7 +313,7 @@
 			copy tilt wc
 			forever $ alloc' $ \c -> do
 				set (fromIntegral start)
-				loopFrom (fromIntegral numchars) $ \i -> do
+				loopFrom (fromIntegral numchars) $ \_i -> do
 					decr
 		
 					withAddr wc decr
@@ -397,3 +413,48 @@
 	-- Any sequence of > and < at the end of a program is a noop.
 	trimend = reverse . dropWhile (`elem` "><") . reverse
 
+-- | Uses the MOVfuscator v1 to build a Linux executable from a BrainFuck
+-- monad action. The executable is implemented entirely using the
+-- MOV instruction. It may be a little slow, especially when loops are
+-- involved.
+--
+-- Prereq: Clone https://github.com/xoreaxeaxeax/movfuscator, build the v1
+-- brainfuck to MOV compiler (in the poc/) directory, and put it in PATH.
+-- Also apt-get install nasm.
+compile :: FilePath -> BrainFuck () -> IO ()
+compile dest b = movfuscate b >>= nasm dest >>= ld dest
+
+type ASM = String
+
+movfuscate :: BrainFuck () -> IO ASM
+movfuscate b = do
+	(Just hin, Just hout, Nothing, h) <- createProcess $
+		(proc "movfuscator" [])
+			{ std_out = CreatePipe
+			, std_in = CreatePipe
+			}
+	hPutStr hin $ optimize $ brainfuck b
+	hClose hin
+	asm <- hGetContents hout
+	writeFile "asm" asm
+	c <- waitForProcess h
+	case c of
+		ExitSuccess -> return ()
+		_ -> error ("movfuscator exited nonzero")
+	return asm
+
+nasm :: FilePath -> ASM -> IO FilePath
+nasm dest a = do
+	-- nasm needs a real file, can't use stdin
+	writeFile asmfile a
+	callProcess "nasm" ["-felf", asmfile, "-o", objfile]
+	removeFile asmfile
+	return objfile
+  where
+	asmfile = dest ++ ".asm"
+	objfile = dest ++ ".o"
+
+ld :: FilePath -> FilePath -> IO ()
+ld dest objfile = do
+	callProcess "ld" ["-melf_i386", objfile, "-o", dest]
+	removeFile objfile
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,5 @@
+{- cabal setup file -}
+
 import Distribution.Simple
+
 main = defaultMain
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.4.0
+Version: 0.5.0
 Cabal-Version: >= 1.8
 License: BSD3
 Maintainer: Joey Hess <id@joeyh.name>
@@ -12,12 +12,13 @@
 Synopsis: BrainFuck monad
 Description:
  This is a BrainFuck monad, for generating brainfuck programs.
+Extra-Source-Files: CHANGELOG
 
 Library
-  GHC-Options: -Wall
+  GHC-Options: -Wall -fno-warn-tabs
   Exposed-Modules: Control.Monad.BrainFuck
-  Build-Depends: base (>= 4.5), base < 5
+  Build-Depends: base (>= 4.5), base < 5, process, directory
 
 source-repository head
   type: git
-  location: git://git.kitenet.net/brainfuck-monad.git
+  location: git://git.joeyh.name/brainfuck-monad.git
