Another Brainfuck interpreter in Haskell
I find this very difficult to read without any logical line breaks or function types given. I.e., you should leave a blank line between definitions for different functions, and every top-level definition should be given a type signature.

fromList :: [a] -&gt; ZL a
fromList []     = EM
fromList (x:xs) = ZL [] x xs

zprv :: ZL a -&gt; ZL a
zprv EM               = EM
zprv (ZL []     x rs) = EM
zprv (ZL (l:ls) x rs) = ZL ls l (x:rs)

-- &amp;c...


zmap is a partial function, and it isn't acting much like a mapping as it only modifies the current element in your given definition. Maybe zapp is a better name? (Or poke, or prod, or...)

zapp :: (a -&gt; a) -&gt; ZL a -&gt; ZL a
zapp _ EM           = EM             -- Or, raise a descriptive `error`
zapp f (ZL ls x rs) = ZL ls (f x) rs


The definition of run is extremely long and not very semantic, rewrite it to be the composition of smaller, more compositional, more meaningful functions.

zinc :: (Num a) =&gt; ZL a -&gt; ZL a
zinc = zapp (+1)

zdec :: (Num a) =&gt; ZL a -&gt; ZL a
zdec = zapp (subtract 1)

zjmp :: (ZL a -&gt; ZL a) -&gt; Int -&gt; ZL a -&gt; ZL a
zjmp _   1  i@(ZL _ ']' _) = znxt i
zjmp _ (-1) i@(ZL _ '[' _) = znxt i
zjmp d   n  i@(ZL l '[' r) = zjmp d (n+1) (d i)
zjmp d   n  i@(ZL l ']' r) = zjmp d (n-1) (d i)
zjmp d   n  i@(ZL l   _ r) = zjmp d n     (d i)

interpret :: ZL Int -&gt; ZL Char -&gt; IO ()
interpret _                 EM          = return ()
interpret m              i@(ZL _ '&gt;' _) = interpret (znxt m) (znxt i)
interpret m              i@(ZL _ '&lt;' _) = interpret (zprv m) (znxt i)
interpret m              i@(ZL _ '+' _) = interpret (zinc m) (znxt i)
interpret m              i@(ZL _ '-' _) = interpret (zdec m) (znxt i)
interpret m@(ZL _  x _ ) i@(ZL _ '[' _) = interpret m (if x /= 0 then znxt i else zjmp znxt 0 i)
interpret m@(ZL _  x _ ) i@(ZL _ ']' _) = interpret m (if x == 0 then znxt i else zjmp zprv 0 i)
interpret m@(ZL _  x _ ) i@(ZL _ '.' _) = putChar (toEnum x) &gt;&gt; interpret m (znxt i)
interpret m@(ZL ml _ mr) i@(ZL _ ',' _) = getChar &gt;&gt;= \x -&gt; interpret (ZL ml (fromEnum x) mr) (znxt i)
interpret m              i@(ZL _ _   _) = interpret m (znxt i) -- Comment `Char`

run :: String -&gt; IO ()
run program = interpret tape (fromList program)
    where
        tape :: ZL Int
        tape = fromList (repeat 0)


Your usage of do is redundant in main. You can either just drop the word do, or write it more idiomatically as&mdash;

main :: IO ()
main = do
          args &lt;- getArgs
          case args of
              [x] -&gt; do
                        program &lt;- readFile x
                        run program
              _   -&gt; usage
    where
        usage = putStrLn "Usage: bf FILE"