As I mentioned in the racket-mode thread, but should probably mention here for the community. I figured out a great way to run a command loop in emacs. Instead of hitting F5 to enter the racket-mode repl, run C-u M-x compile. This will run your command loop in comint mode, so you get a lot of features for free. Adding the C-u prefix gives two-way prompt style communication with your program. In this mode, the history is your command loop's own history (rather than the Racket repl history), which is a very nice feature to get for free.
I suppose another possible design would be for the user program's input/output to get its own dedicated UI -- such as a completely different buffer in Emacs.
IIRC DrRacket sort of does this for user program input -- a temporary input box appears -- but the resulting input and all user program output still goes in the interactions pane.
(I actually considered that kind of UX but it seemed impossible to achieve well with a separate front end process in Emacs. For Emacs, I think it would be cleaner to use a dedicated I/O buffer, which could e.g. be put in comint-mode as @acarrico said or otherwise customized differently.)
Some existing precedent for this split is logger output: In command-line Racket, this gets written to stdout -- but in both DrR and Racket Mode, this gets its own UI. Since logger output is async, this is particularly helpful.
Having said that, I've heard from one user who doesn't love the separated logger output. There are tradeoffs. The command line approach, with everything dumped together, can feel more immediate and complete, and regardless of async there is some useful sense of interleaved time-ordering. (And some people may not care that the resulting mix is "hopeless", and the original structure can only be recovered through unreliable regexps).
Maybe the "most correct" UI would use one window/pane, time flowing down, and separate columns for REPL per se, user I/O, logger, etc. That would avoid "hiding" anything, preserve time order, and preserve structure. How usable it would be... idk.
Ah, this is a nice idea! We didn't consider segregating the user program output from the REPL output! That would have made the implementation simpler too, I believe.
Bonus points for raw mode. But actually just choosing among racket-repl or comint is working pretty well for me. Life would compete if I figured out how to launch into term-mode if I needed raw i/o.