Ordinary Data Processing Task in Haskell: Vague Misgivings
recursive part of minBal is mapM_
multiple get is better to refactor into one
get - process - put part of minBal is modify
state monad is not necessary - you can use plain foldr instead of mapM_ and modify
runningBal is better to implement using scanr. Then zip running balances and source list and foldr the resulting list of tuples
use minimum to find the minimum


Here is a more idiomatic approach to minBal:

runningBal' = scanl1 (+) . map amt

rb l = zip (runningBal' l) l

mb l = minimumBy (compare `on` fst) l

minDay = mb . rb

minBal' l = DtdBal { 
    runningBal = fst $ last runningBals, 
    lowDt = dt $ snd md, 
    lowBal = fst md } 
    where
        runningBals = rb l
        md = minDay l


You can inline all the small functions for the final code but that's the order I created them in. Note that rb is calculated twice, but I was not sure if you really need the final balance. In your algorithm it was a byproduct.

main can be rewritten too:

main' = (parseFromFile sched &gt;=&gt; process &gt;=&gt; print) "escrow.txt" where
    process (Right l) = return $ minBal' l
    process (Left _) = error "Oops"


Basically, putStrLn . show is print and composition is your friend. &gt;=&gt; is monadic variant of .. It's advantage over &gt;&gt;= is associativity - it lets you refactor your code more easily.

Here is a shorter version of minBal' which also saves a few calculations, but last is still O(N):

minBal' l = DtdBal { 
    runningBal = last runningBals, 
    lowDt = dt $ snd md, 
    lowBal = fst md } 
    where
        md = minimumBy (compare `on` fst) $ zip runningBals l
        runningBals = scanl1 (+) $ map amt l


Let me know how this works for very large files.