I can't help but think that that executable could have been much smaller, like < 50 lines, in Haskell. First stab at it, with less-rich command-line arguments:
import Prelude hiding (getContents)
import Control.Exception
import Control.Concurrent
import System.Environment -- for getArgs
import Data.ByteString (getContents) -- for strictness
import System.IO hiding (getContents)
spin :: String -> Handle -> IO ()
spin s h = sequence_ $ cycle [p " \\", d, p " -", d, p " /", d] where
p c = hPutStr h ('\r' : s ++ c) >> hFlush h
d = threadDelay 100000
main = do
prompt <- getArgs
let actualPrompt = if null prompt then "Loading" else head prompt
sThread <- forkIO (spin actualPrompt stdout)
getContents
throwTo sThread ThreadKilled
I mean there are some serious problems with the above, like that I can't guarantee that Haskell will see the `ByteString.getContents` by itself on one line and use constant memory knowing that the resulting bytestring will not be used... maybe I need something more like `catchIOError (sequence_ $ repeat getChar) (\e -> if IO.isEOFError e then return () else ioError e)` to consume the stream with fixed overhead without blocking... but it seems like argument-handling, printing out usage information, and getting O(1) memory usage can't possibly quintuple this thing's length.